Compare commits

..

37 Commits

Author SHA1 Message Date
a9bca04f1c Move Utils class to utils package 2018-11-22 21:13:01 +04:00
84cdddc4b9 Write a CompositeIterator and use it to clean up entity iteration 2018-11-22 21:12:35 +04:00
4d27a2671a Cleanup Brick.render() 2018-11-22 20:52:20 +04:00
451ca13566 Add missing semicolon. 2018-11-22 18:55:15 +04:00
9e44b1e93f Change desktop resolution to 1/5th of native resolution 2018-11-22 17:39:13 +04:00
7ff4d3307a Add gdx-tools dependency, add TextureSetup class 2018-11-22 17:36:28 +04:00
9e8e00e9af Add random shape and type control to GridLevelLoader 2018-11-22 17:34:18 +04:00
44c3311cd9 Set powerup segment count to 20. 2018-11-22 17:31:28 +04:00
28eb4149ee Change background to black, paddle to white 2018-11-22 17:31:00 +04:00
36ae71afeb Add FileLevelLoader and FileLayout to load levels from json files
Add two levels to assets
2018-11-22 17:30:48 +04:00
90b92b1026 Remember to call super.dispose() in FieldState's dispose() 2018-11-22 17:23:53 +04:00
53feedf407 Pass spritebatch instance to all entity's render methods
Scale spritebatch and shaperenderer projections to PIXEL_PER_METER,
no longer have to scale in each entity's render method
Use a separate spritebatch for font rendering
Dispose the texture atlas
2018-11-22 15:44:13 +04:00
70f142c2fa Render bricks and ball using sprites instead of constructed polygons
Changed field width to 10 blocks instead of 11
2018-11-22 14:55:13 +04:00
bb8d4a41e3 Add hidden (press F12 at main menu) level editor mode
Saves a level.json in the external storage
2018-11-21 15:38:32 +04:00
157a247516 Calculate PIXEL_PER_METER 2018-11-21 15:26:19 +04:00
87f91cc2bc Reorder and add new brick shapes 2018-11-21 15:26:19 +04:00
3fdd394e36 Decreased brick size, increased edge padding, removed brick padding
Field is now 11 bricks wide instead of 10
Extended edge padding to Y=0
2018-11-21 15:26:19 +04:00
2a40bcabdf Use bit-or comparisons to create brick vertices, makes for shorter code
Added new brick shapes
2018-11-21 15:26:19 +04:00
ef698a38c1 Add new brick shapes. 2018-11-21 15:26:19 +04:00
2a398725f5 Override setX and setY in Brick to update box2d body's position.
Clean up Ball and Paddle's overrides
2018-11-21 15:26:19 +04:00
f90f5d5452 Add new abstract FieldState, which contains the Box2d world instance.
PlayState now extends FieldState instead of State.
Entity now takes a FieldState instead of a State instance.
Casts from State to PlayState where necessary in entities.
2018-11-21 15:26:13 +04:00
958232b2ff Remove unused Color import from Brick 2018-11-20 16:14:42 +04:00
989bb46d64 Add LevelLoader interface and Level class.
Add GridLevelLoader implementation, use to load initial level
Add logic to return to main menu when there's no more levels, or load the next
the next level
2018-11-20 16:14:15 +04:00
1aeab73cd0 Delete bricks that go below the bottom of the play field 2018-11-20 12:15:55 +04:00
5611bbc611 Add BrickLayout interace with an implementing GridLayout
Use new GridLayout to generate initial level
Remove some constructors in Birck
Add Color to BrickType enum, alter Brick to use it
2018-11-20 11:01:54 +04:00
719c32502c No longer allow balls to collect powerups 2018-11-19 23:41:48 +04:00
9df81ee854 Add dispose() to Entity and implement in Brick 2018-11-15 23:15:07 +04:00
e116f1064d Add additional brick shapes 2018-11-15 22:04:29 +04:00
4fa5841fb2 Fix correction impulse on ball 2018-11-15 22:03:12 +04:00
f70dc67878 Begin adding support for rendering different shaped bricks 2018-11-15 20:09:48 +04:00
64e00c1a1a Treat brick coordinates as their center 2018-11-15 18:19:54 +04:00
cb90c949ff New MINIMUM_ANGLE constant in Ball, currently PI/16
Apply impulses to ball when angle relative to horizontal axis is less
than MINIMUM_ANGLE. Prevents balls getting stuck going horizontally
2018-11-15 16:31:42 +04:00
998286de8d Ensure balls collide with the shield 2018-11-15 14:53:14 +04:00
9eac3353b6 Use instance bodies array 2018-11-15 14:48:32 +04:00
adebc42c16 Add Box2d collision filtering, allow collecting power ups with balls 2018-11-15 14:22:42 +04:00
74aa10de04 Refactor to use libGdx Array instead of java ArrayList
Render bricks with their box2d angle
Add ball density = 1f
2018-11-15 13:43:48 +04:00
b44b48097c Update paddle.update() to handle edge collision more nicely + cleaner code
Calculates an adjust variable which locates the paddle at exactly the
screen edge if a regular speed * dt move would put it past. Applies
the same adjust to stuck balls so they don't drift.
2018-11-15 12:24:33 +04:00
73 changed files with 2246 additions and 241 deletions

View File

@ -44,6 +44,7 @@ project(":desktop") {
dependencies {
compile project(":core")
compile "com.badlogicgames.gdx:gdx-tools:$gdxVersion"
compile "com.badlogicgames.gdx:gdx-backend-lwjgl:$gdxVersion"
compile "com.badlogicgames.gdx:gdx-platform:$gdxVersion:natives-desktop"
compile "com.badlogicgames.gdx:gdx-box2d-platform:$gdxVersion:natives-desktop"

View File

@ -0,0 +1,358 @@
{
bricks: [
{
row: 15
type: HARD
shape: RECTANGLE
}
{
row: 16
type: STANDARD_50
shape: RECTANGLE
}
{
row: 17
type: STANDARD_80
shape: RECTANGLE
}
{
row: 18
type: STANDARD_60
shape: RECTANGLE
}
{
row: 19
type: STANDARD_70
shape: RECTANGLE
}
{
row: 20
type: STANDARD_40
shape: RECTANGLE
}
{
col: 1
row: 15
type: HARD
shape: RECTANGLE
}
{
col: 1
row: 16
type: STANDARD_50
shape: RECTANGLE
}
{
col: 1
row: 17
type: STANDARD_80
shape: RECTANGLE
}
{
col: 1
row: 18
type: STANDARD_60
shape: RECTANGLE
}
{
col: 1
row: 19
type: STANDARD_70
shape: RECTANGLE
}
{
col: 1
row: 20
type: STANDARD_40
shape: RECTANGLE
}
{
col: 2
row: 15
type: HARD
shape: RECTANGLE
}
{
col: 2
row: 16
type: STANDARD_50
shape: RECTANGLE
}
{
col: 2
row: 17
type: STANDARD_80
shape: RECTANGLE
}
{
col: 2
row: 18
type: STANDARD_60
shape: RECTANGLE
}
{
col: 2
row: 19
type: STANDARD_70
shape: RECTANGLE
}
{
col: 2
row: 20
type: STANDARD_40
shape: RECTANGLE
}
{
col: 3
row: 15
type: HARD
shape: RECTANGLE
}
{
col: 3
row: 16
type: STANDARD_50
shape: RECTANGLE
}
{
col: 3
row: 17
type: STANDARD_80
shape: RECTANGLE
}
{
col: 3
row: 18
type: STANDARD_60
shape: RECTANGLE
}
{
col: 3
row: 19
type: STANDARD_70
shape: RECTANGLE
}
{
col: 3
row: 20
type: STANDARD_40
shape: RECTANGLE
}
{
col: 4
row: 15
type: HARD
shape: RECTANGLE
}
{
col: 4
row: 16
type: STANDARD_50
shape: RECTANGLE
}
{
col: 4
row: 17
type: STANDARD_80
shape: RECTANGLE
}
{
col: 4
row: 18
type: STANDARD_60
shape: RECTANGLE
}
{
col: 4
row: 19
type: STANDARD_70
shape: RECTANGLE
}
{
col: 4
row: 20
type: STANDARD_40
shape: RECTANGLE
}
{
col: 5
row: 15
type: HARD
shape: RECTANGLE
}
{
col: 5
row: 16
type: STANDARD_50
shape: RECTANGLE
}
{
col: 5
row: 17
type: STANDARD_80
shape: RECTANGLE
}
{
col: 5
row: 18
type: STANDARD_60
shape: RECTANGLE
}
{
col: 5
row: 19
type: STANDARD_70
shape: RECTANGLE
}
{
col: 5
row: 20
type: STANDARD_40
shape: RECTANGLE
}
{
col: 6
row: 15
type: HARD
shape: RECTANGLE
}
{
col: 6
row: 16
type: STANDARD_50
shape: RECTANGLE
}
{
col: 6
row: 17
type: STANDARD_80
shape: RECTANGLE
}
{
col: 6
row: 18
type: STANDARD_60
shape: RECTANGLE
}
{
col: 6
row: 19
type: STANDARD_70
shape: RECTANGLE
}
{
col: 6
row: 20
type: STANDARD_40
shape: RECTANGLE
}
{
col: 7
row: 15
type: HARD
shape: RECTANGLE
}
{
col: 7
row: 16
type: STANDARD_50
shape: RECTANGLE
}
{
col: 7
row: 17
type: STANDARD_80
shape: RECTANGLE
}
{
col: 7
row: 18
type: STANDARD_60
shape: RECTANGLE
}
{
col: 7
row: 19
type: STANDARD_70
shape: RECTANGLE
}
{
col: 7
row: 20
type: STANDARD_40
shape: RECTANGLE
}
{
col: 8
row: 15
type: HARD
shape: RECTANGLE
}
{
col: 8
row: 16
type: STANDARD_50
shape: RECTANGLE
}
{
col: 8
row: 17
type: STANDARD_80
shape: RECTANGLE
}
{
col: 8
row: 18
type: STANDARD_60
shape: RECTANGLE
}
{
col: 8
row: 19
type: STANDARD_70
shape: RECTANGLE
}
{
col: 8
row: 20
type: STANDARD_40
shape: RECTANGLE
}
{
col: 9
row: 15
type: HARD
shape: RECTANGLE
}
{
col: 9
row: 16
type: STANDARD_50
shape: RECTANGLE
}
{
col: 9
row: 17
type: STANDARD_80
shape: RECTANGLE
}
{
col: 9
row: 18
type: STANDARD_60
shape: RECTANGLE
}
{
col: 9
row: 19
type: STANDARD_70
shape: RECTANGLE
}
{
col: 9
row: 20
type: STANDARD_40
shape: RECTANGLE
}
]
}

View File

@ -0,0 +1,598 @@
{
bricks: [
{
row: 5
type: STANDARD_40
shape: HALF_LOWER_RECTANGLE
}
{
row: 6
type: STANDARD_40
shape: DIAMOND
}
{
row: 7
type: STANDARD_40
shape: DIAMOND
}
{
row: 8
type: STANDARD_40
shape: RECTANGLE
}
{
row: 9
type: STANDARD_40
shape: FULL_LEFT_UP_RIGHT_TRIANGLE
}
{
row: 10
type: STANDARD_40
shape: RIGHT_UP_RIGHT_TRIANGLE
}
{
col: 1
row: 5
type: STANDARD_40
shape: HALF_LOWER_RECTANGLE
}
{
col: 1
row: 6
type: STANDARD_60
shape: DIAMOND
}
{
col: 1
row: 7
type: STANDARD_40
shape: DIAMOND
}
{
col: 1
row: 8
type: STANDARD_40
shape: RECTANGLE
}
{
col: 1
row: 9
type: STANDARD_50
shape: RECTANGLE
}
{
col: 1
row: 10
type: STANDARD_50
shape: RECTANGLE
}
{
col: 1
row: 11
type: STANDARD_40
shape: FULL_LEFT_UP_RIGHT_TRIANGLE
}
{
col: 1
row: 12
type: STANDARD_40
shape: RIGHT_UP_RIGHT_TRIANGLE
}
{
col: 2
row: 5
type: STANDARD_40
shape: HALF_LOWER_RECTANGLE
}
{
col: 2
row: 6
type: STANDARD_60
shape: DIAMOND
}
{
col: 2
row: 7
type: STANDARD_50
shape: DIAMOND
}
{
col: 2
row: 8
type: STANDARD_40
shape: RECTANGLE
}
{
col: 2
row: 9
type: STANDARD_50
shape: RECTANGLE
}
{
col: 2
row: 10
type: STANDARD_50
shape: RECTANGLE
}
{
col: 2
row: 11
type: STANDARD_50
shape: RECTANGLE
}
{
col: 2
row: 12
type: STANDARD_50
shape: RECTANGLE
}
{
col: 2
row: 13
type: STANDARD_40
shape: FULL_LEFT_UP_RIGHT_TRIANGLE
}
{
col: 2
row: 14
type: STANDARD_40
shape: RIGHT_UP_RIGHT_TRIANGLE
}
{
col: 3
row: 5
type: STANDARD_40
shape: HALF_LOWER_RECTANGLE
}
{
col: 3
row: 6
type: STANDARD_60
shape: DIAMOND
}
{
col: 3
row: 7
type: STANDARD_40
shape: DIAMOND
}
{
col: 3
row: 8
type: STANDARD_40
shape: RECTANGLE
}
{
col: 3
row: 9
type: STANDARD_50
shape: RECTANGLE
}
{
col: 3
row: 10
type: STANDARD_50
shape: RECTANGLE
}
{
col: 3
row: 11
type: STANDARD_50
shape: RECTANGLE
}
{
col: 3
row: 12
type: STANDARD_50
shape: RECTANGLE
}
{
col: 3
row: 13
type: STANDARD_80
shape: RECTANGLE
}
{
col: 3
row: 14
type: STANDARD_80
shape: RECTANGLE
}
{
col: 3
row: 15
type: STANDARD_40
shape: FULL_LEFT_UP_RIGHT_TRIANGLE
}
{
col: 3
row: 16
type: STANDARD_40
shape: RIGHT_UP_RIGHT_TRIANGLE
}
{
col: 4
row: 5
type: STANDARD_40
shape: HALF_LOWER_RECTANGLE
}
{
col: 4
row: 6
type: STANDARD_40
shape: DIAMOND
}
{
col: 4
row: 7
type: STANDARD_50
shape: DIAMOND
}
{
col: 4
row: 8
type: STANDARD_40
shape: RECTANGLE
}
{
col: 4
row: 9
type: STANDARD_50
shape: RECTANGLE
}
{
col: 4
row: 10
type: STANDARD_50
shape: RECTANGLE
}
{
col: 4
row: 11
type: STANDARD_50
shape: RECTANGLE
}
{
col: 4
row: 12
type: STANDARD_50
shape: RECTANGLE
}
{
col: 4
row: 13
type: STANDARD_80
shape: RECTANGLE
}
{
col: 4
row: 14
type: STANDARD_80
shape: RECTANGLE
}
{
col: 4
row: 15
type: STANDARD_70
shape: RECTANGLE
}
{
col: 4
row: 16
type: STANDARD_60
shape: RECTANGLE
}
{
col: 4
row: 17
type: STANDARD_40
shape: FULL_LEFT_UP_RIGHT_TRIANGLE
}
{
col: 4
row: 18
type: STANDARD_40
shape: RIGHT_UP_RIGHT_TRIANGLE
}
{
col: 5
row: 5
type: STANDARD_40
shape: HALF_LOWER_RECTANGLE
}
{
col: 5
row: 6
type: STANDARD_40
shape: DIAMOND
}
{
col: 5
row: 7
type: STANDARD_50
shape: DIAMOND
}
{
col: 5
row: 8
type: STANDARD_40
shape: RECTANGLE
}
{
col: 5
row: 9
type: STANDARD_50
shape: RECTANGLE
}
{
col: 5
row: 10
type: STANDARD_50
shape: RECTANGLE
}
{
col: 5
row: 11
type: STANDARD_50
shape: RECTANGLE
}
{
col: 5
row: 12
type: STANDARD_50
shape: RECTANGLE
}
{
col: 5
row: 13
type: STANDARD_80
shape: RECTANGLE
}
{
col: 5
row: 14
type: STANDARD_80
shape: RECTANGLE
}
{
col: 5
row: 15
type: STANDARD_70
shape: RECTANGLE
}
{
col: 5
row: 16
type: STANDARD_60
shape: RECTANGLE
}
{
col: 5
row: 17
type: STANDARD_40
shape: FULL_UP_LEFT_TRIANGLE
}
{
col: 5
row: 18
type: STANDARD_40
shape: LEFT_UP_LEFT_TRIANGLE
}
{
col: 6
row: 5
type: STANDARD_40
shape: HALF_LOWER_RECTANGLE
}
{
col: 6
row: 6
type: STANDARD_60
shape: DIAMOND
}
{
col: 6
row: 7
type: STANDARD_40
shape: DIAMOND
}
{
col: 6
row: 8
type: STANDARD_40
shape: RECTANGLE
}
{
col: 6
row: 9
type: STANDARD_50
shape: RECTANGLE
}
{
col: 6
row: 10
type: STANDARD_50
shape: RECTANGLE
}
{
col: 6
row: 11
type: STANDARD_50
shape: RECTANGLE
}
{
col: 6
row: 12
type: STANDARD_50
shape: RECTANGLE
}
{
col: 6
row: 13
type: STANDARD_80
shape: RECTANGLE
}
{
col: 6
row: 14
type: STANDARD_80
shape: RECTANGLE
}
{
col: 6
row: 15
type: STANDARD_40
shape: FULL_UP_LEFT_TRIANGLE
}
{
col: 6
row: 16
type: STANDARD_40
shape: LEFT_UP_LEFT_TRIANGLE
}
{
col: 7
row: 5
type: STANDARD_40
shape: HALF_LOWER_RECTANGLE
}
{
col: 7
row: 6
type: STANDARD_60
shape: DIAMOND
}
{
col: 7
row: 7
type: STANDARD_50
shape: DIAMOND
}
{
col: 7
row: 8
type: STANDARD_40
shape: RECTANGLE
}
{
col: 7
row: 9
type: STANDARD_50
shape: RECTANGLE
}
{
col: 7
row: 10
type: STANDARD_50
shape: RECTANGLE
}
{
col: 7
row: 11
type: STANDARD_50
shape: RECTANGLE
}
{
col: 7
row: 12
type: STANDARD_50
shape: RECTANGLE
}
{
col: 7
row: 13
type: STANDARD_40
shape: FULL_UP_LEFT_TRIANGLE
}
{
col: 7
row: 14
type: STANDARD_40
shape: LEFT_UP_LEFT_TRIANGLE
}
{
col: 8
row: 5
type: STANDARD_40
shape: HALF_LOWER_RECTANGLE
}
{
col: 8
row: 6
type: STANDARD_60
shape: DIAMOND
}
{
col: 8
row: 7
type: STANDARD_40
shape: DIAMOND
}
{
col: 8
row: 8
type: STANDARD_40
shape: RECTANGLE
}
{
col: 8
row: 9
type: STANDARD_50
shape: RECTANGLE
}
{
col: 8
row: 10
type: STANDARD_50
shape: RECTANGLE
}
{
col: 8
row: 11
type: STANDARD_40
shape: FULL_UP_LEFT_TRIANGLE
}
{
col: 8
row: 12
type: STANDARD_40
shape: LEFT_UP_LEFT_TRIANGLE
}
{
col: 9
row: 5
type: STANDARD_40
shape: HALF_LOWER_RECTANGLE
}
{
col: 9
row: 6
type: STANDARD_40
shape: DIAMOND
}
{
col: 9
row: 7
type: STANDARD_40
shape: DIAMOND
}
{
col: 9
row: 8
type: STANDARD_40
shape: RECTANGLE
}
{
col: 9
row: 9
type: STANDARD_40
shape: FULL_UP_LEFT_TRIANGLE
}
{
col: 9
row: 10
type: STANDARD_40
shape: LEFT_UP_LEFT_TRIANGLE
}
]
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1013 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 963 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 730 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 678 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 732 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 683 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 534 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

257
core/assets/textures.atlas Normal file
View File

@ -0,0 +1,257 @@
textures.png
size: 1024,1024
format: RGBA8888
filter: MipMapLinearLinear,MipMapLinearLinear
repeat: none
ball
rotate: false
xy: 800, 824
size: 128, 128
orig: 128, 128
offset: 0, 0
index: -1
brick_DIAMOND
rotate: false
xy: 8, 824
size: 256, 128
orig: 256, 128
offset: 0, 0
index: -1
brick_DOWN_LEFT_TRIANGLE
rotate: false
xy: 8, 688
size: 256, 128
orig: 256, 128
offset: 0, 0
index: -1
brick_DOWN_RIGHT_TRIANGLE
rotate: false
xy: 272, 824
size: 256, 128
orig: 256, 128
offset: 0, 0
index: -1
brick_DOWN_TRIANGLE
rotate: false
xy: 8, 552
size: 256, 128
orig: 256, 128
offset: 0, 0
index: -1
brick_FULL_DOWN_LEFT_TRIANGLE
rotate: false
xy: 272, 688
size: 256, 128
orig: 256, 128
offset: 0, 0
index: -1
brick_FULL_HALF_DOWN_TRIANGLE
rotate: false
xy: 536, 824
size: 256, 128
orig: 256, 128
offset: 0, 0
index: -1
brick_FULL_HALF_LEFT_TRIANGLE
rotate: false
xy: 8, 416
size: 256, 128
orig: 256, 128
offset: 0, 0
index: -1
brick_FULL_HALF_RIGHT_TRIANGLE
rotate: false
xy: 272, 552
size: 256, 128
orig: 256, 128
offset: 0, 0
index: -1
brick_FULL_HALF_UP_TRIANGLE
rotate: false
xy: 536, 688
size: 256, 128
orig: 256, 128
offset: 0, 0
index: -1
brick_FULL_LEFT_DOWN_RIGHT_TRIANGLE
rotate: false
xy: 8, 280
size: 256, 128
orig: 256, 128
offset: 0, 0
index: -1
brick_FULL_LEFT_UP_RIGHT_TRIANGLE
rotate: false
xy: 272, 416
size: 256, 128
orig: 256, 128
offset: 0, 0
index: -1
brick_FULL_UP_LEFT_TRIANGLE
rotate: false
xy: 536, 552
size: 256, 128
orig: 256, 128
offset: 0, 0
index: -1
brick_HALF_DOWN_TRIANGLE
rotate: false
xy: 8, 144
size: 256, 128
orig: 256, 128
offset: 0, 0
index: -1
brick_HALF_LEFT_SQUARE
rotate: false
xy: 272, 280
size: 256, 128
orig: 256, 128
offset: 0, 0
index: -1
brick_HALF_LEFT_TRIANGLE
rotate: false
xy: 536, 416
size: 256, 128
orig: 256, 128
offset: 0, 0
index: -1
brick_HALF_LOWER_RECTANGLE
rotate: false
xy: 8, 8
size: 256, 128
orig: 256, 128
offset: 0, 0
index: -1
brick_HALF_RIGHT_SQUARE
rotate: false
xy: 272, 144
size: 256, 128
orig: 256, 128
offset: 0, 0
index: -1
brick_HALF_RIGHT_TRIANGLE
rotate: false
xy: 536, 280
size: 256, 128
orig: 256, 128
offset: 0, 0
index: -1
brick_HALF_UPPER_RECTANGLE
rotate: false
xy: 272, 8
size: 256, 128
orig: 256, 128
offset: 0, 0
index: -1
brick_HALF_UP_TRIANGLE
rotate: false
xy: 536, 144
size: 256, 128
orig: 256, 128
offset: 0, 0
index: -1
brick_LEFT_DOWN_LEFT_TRIANGLE
rotate: false
xy: 536, 8
size: 256, 128
orig: 256, 128
offset: 0, 0
index: -1
textures2.png
size: 1024,1024
format: RGBA8888
filter: MipMapLinearLinear,MipMapLinearLinear
repeat: none
brick_LEFT_DOWN_RIGHT_TRIANGLE
rotate: false
xy: 8, 688
size: 256, 128
orig: 256, 128
offset: 0, 0
index: -1
brick_LEFT_TRIANGLE
rotate: false
xy: 8, 552
size: 256, 128
orig: 256, 128
offset: 0, 0
index: -1
brick_LEFT_UP_LEFT_TRIANGLE
rotate: false
xy: 272, 688
size: 256, 128
orig: 256, 128
offset: 0, 0
index: -1
brick_LEFT_UP_RIGHT_TRIANGLE
rotate: false
xy: 8, 416
size: 256, 128
orig: 256, 128
offset: 0, 0
index: -1
brick_RECTANGLE
rotate: false
xy: 272, 552
size: 256, 128
orig: 256, 128
offset: 0, 0
index: -1
brick_RIGHT_DOWN_LEFT_TRIANGLE
rotate: false
xy: 536, 688
size: 256, 128
orig: 256, 128
offset: 0, 0
index: -1
brick_RIGHT_DOWN_RIGHT_TRIANGLE
rotate: false
xy: 8, 280
size: 256, 128
orig: 256, 128
offset: 0, 0
index: -1
brick_RIGHT_TRIANGLE
rotate: false
xy: 272, 416
size: 256, 128
orig: 256, 128
offset: 0, 0
index: -1
brick_RIGHT_UP_LEFT_TRIANGLE
rotate: false
xy: 536, 552
size: 256, 128
orig: 256, 128
offset: 0, 0
index: -1
brick_RIGHT_UP_RIGHT_TRIANGLE
rotate: false
xy: 8, 144
size: 256, 128
orig: 256, 128
offset: 0, 0
index: -1
brick_UP_LEFT_TRIANGLE
rotate: false
xy: 272, 280
size: 256, 128
orig: 256, 128
offset: 0, 0
index: -1
brick_UP_RIGHT_TRIANGLE
rotate: false
xy: 536, 416
size: 256, 128
orig: 256, 128
offset: 0, 0
index: -1
brick_UP_TRIANGLE
rotate: false
xy: 8, 8
size: 256, 128
orig: 256, 128
offset: 0, 0
index: -1

BIN
core/assets/textures.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 41 KiB

BIN
core/assets/textures2.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

View File

@ -2,15 +2,19 @@ package com.me.brickbuster;
import com.badlogic.gdx.Game;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.assets.AssetManager;
import com.badlogic.gdx.graphics.GL20;
import com.badlogic.gdx.graphics.OrthographicCamera;
import com.badlogic.gdx.graphics.Texture;
import com.badlogic.gdx.graphics.g2d.BitmapFont;
import com.badlogic.gdx.graphics.g2d.PolygonSpriteBatch;
import com.badlogic.gdx.graphics.g2d.SpriteBatch;
import com.badlogic.gdx.graphics.glutils.ShapeRenderer;
import com.badlogic.gdx.math.Matrix4;
import com.badlogic.gdx.utils.viewport.FitViewport;
import com.badlogic.gdx.utils.viewport.Viewport;
import com.me.brickbuster.state.MenuState;
import com.me.brickbuster.state.PlayState;
public class BrickBuster extends Game {
@ -24,8 +28,11 @@ public class BrickBuster extends Game {
public BitmapFont font;
public SpriteBatch sb;
public SpriteBatch fb;
public ShapeRenderer sr;
public AssetManager assets;
@Override
public void create () {
cam = new OrthographicCamera();
@ -37,14 +44,17 @@ public class BrickBuster extends Game {
font.getRegion().getTexture().setFilter(Texture.TextureFilter.Linear, Texture.TextureFilter.Linear);
sb = new SpriteBatch();
fb = new SpriteBatch();
sr = new ShapeRenderer();
assets = new AssetManager();
setScreen(new MenuState(this));
}
@Override
public void render () {
Gdx.gl.glClearColor(0.5f,1,1,1);
Gdx.gl.glClearColor(0f,0f,0f,1);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
// Render the current Screen (State)
super.render();
@ -54,8 +64,10 @@ public class BrickBuster extends Game {
public void resize(int width, int height) {
viewport.update(width, height);
sb.setProjectionMatrix(cam.combined);
sr.setProjectionMatrix(cam.combined);
Matrix4 projection = cam.combined.cpy().scl(PlayState.PIXEL_PER_METER);
sb.setProjectionMatrix(projection);
fb.setProjectionMatrix(cam.combined);
sr.setProjectionMatrix(projection);
super.resize(width, height);
}

View File

@ -2,15 +2,15 @@ package com.me.brickbuster.entity;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.graphics.Color;
import com.badlogic.gdx.graphics.g2d.SpriteBatch;
import com.badlogic.gdx.graphics.g2d.TextureRegion;
import com.badlogic.gdx.graphics.glutils.ShapeRenderer;
import com.badlogic.gdx.graphics.glutils.ShapeRenderer.ShapeType;
import com.badlogic.gdx.math.MathUtils;
import com.badlogic.gdx.math.Vector2;
import com.badlogic.gdx.physics.box2d.Body;
import com.badlogic.gdx.physics.box2d.BodyDef;
import com.badlogic.gdx.physics.box2d.CircleShape;
import com.badlogic.gdx.physics.box2d.FixtureDef;
import com.badlogic.gdx.physics.box2d.*;
import com.me.brickbuster.physics.CollisionListener;
import com.me.brickbuster.physics.EntityType;
import com.me.brickbuster.physics.PhysicsBody;
import com.me.brickbuster.state.PlayState;
@ -22,26 +22,33 @@ public class Ball extends Entity implements PhysicsBody, CollisionListener {
public static final float BOOST_SPEED = 55;
public static final int BLOCKS_FOR_BOOST = 39;
public static final float MINIMUM_ANGLE = MathUtils.PI/16;
public static final float CORRECTION_IMPULSE = 3f;
private float speed;
private boolean isStuck = true;
private boolean touchedPaddle = false;
private TextureRegion texture;
private Body body;
public Ball(PlayState state) {
super(state, state.paddle.getX(), state.paddle.getY() + Paddle.PADDLE_HEIGHT + RADIUS);
this.speed = state.bricks.size() > BLOCKS_FOR_BOOST? DEFAULT_SPEED : BOOST_SPEED;
this.speed = state.bricks.size > BLOCKS_FOR_BOOST? DEFAULT_SPEED : BOOST_SPEED;
texture = state.textures.findRegion("ball");
createBody();
}
@Override
public void render(ShapeRenderer sr) {
sr.begin(ShapeType.Filled);
sr.setColor(BALL_COLOR);
sr.circle(pos.x * PlayState.PIXEL_PER_METER,
pos.y * PlayState.PIXEL_PER_METER,
RADIUS * PlayState.PIXEL_PER_METER);
sr.end();
public void render(SpriteBatch sb, ShapeRenderer sr) {
sb.setColor(Color.WHITE);
sb.draw(texture, pos.x - RADIUS,
pos.y - RADIUS,
RADIUS*2,
RADIUS*2);
}
@Override
@ -58,11 +65,19 @@ public class Ball extends Entity implements PhysicsBody, CollisionListener {
touchedPaddle = false;
}
if (getY() + RADIUS < 0) {
if (pos.y + RADIUS < 0) {
deleted = true;
return;
}
body.setLinearVelocity(body.getLinearVelocity().nor().scl(speed));
Vector2 velocity = body.getLinearVelocity();
body.setLinearVelocity(velocity.nor().scl(speed));
float rad = velocity.angleRad();
if (Math.abs(rad) < MINIMUM_ANGLE || Math.abs(rad) > MathUtils.PI - MINIMUM_ANGLE) {
Vector2 impulse = new Vector2(0, rad > 0? CORRECTION_IMPULSE : -CORRECTION_IMPULSE);
body.applyLinearImpulse(impulse, pos, true);
}
}
@Override
@ -83,6 +98,11 @@ public class Ball extends Entity implements PhysicsBody, CollisionListener {
ballFixture.shape = ballShape;
ballFixture.restitution = 1f;
ballFixture.friction = 0f;
ballFixture.density = 1f;
ballFixture.filter.categoryBits = EntityType.BALL;
ballFixture.filter.maskBits = EntityType.BOUNDARY | EntityType.BRICK
| EntityType.PADDLE | EntityType.SHIELD;
body = state.world.createBody(ballBody);
body.createFixture(ballFixture);
@ -107,32 +127,31 @@ public class Ball extends Entity implements PhysicsBody, CollisionListener {
}
public Vector2 paddleReflectAngle() {
float trim = state.paddle.getWidth() * 0.10f;
float rel = MathUtils.clamp((pos.x - state.paddle.getX()) + (state.paddle.getWidth()/2),
trim, state.paddle.getWidth()-trim);
float newAngle = MathUtils.PI - (MathUtils.PI * (rel / state.paddle.getWidth()));
Paddle paddle = ((PlayState) state).paddle;
float rel = (pos.x - paddle.getX()) + (paddle.getWidth()/2);
float newAngle = MathUtils.PI - (MathUtils.PI * (rel / paddle.getWidth()));
newAngle = MathUtils.clamp(newAngle, MINIMUM_ANGLE, MathUtils.PI-MINIMUM_ANGLE);
return new Vector2(MathUtils.cos(newAngle), MathUtils.sin(newAngle));
}
public void launch() {
Vector2 direction;
if (state.paddle.isSticky()) {
if (((PlayState) state).paddle.isSticky()) {
direction = paddleReflectAngle();
} else {
// launch at random angle between 135 and 45 degrees
float angle = MathUtils.random(MathUtils.PI/2) + MathUtils.PI/4;
direction = new Vector2(MathUtils.cos(angle), MathUtils.sin(angle));
}
body.setLinearVelocity(direction.scl(speed));
isStuck = false;
}
public void paddleCollision() {
if (state.paddle.isSticky()) {
if (((PlayState) state).paddle.isSticky()) {
isStuck = true;
body.setLinearVelocity(new Vector2());
setY(state.paddle.getY() + Paddle.PADDLE_HEIGHT + RADIUS);
setY(((PlayState) state).paddle.getY() + Paddle.PADDLE_HEIGHT + RADIUS);
return;
}
body.setLinearVelocity(paddleReflectAngle().scl(speed));
@ -141,17 +160,13 @@ public class Ball extends Entity implements PhysicsBody, CollisionListener {
@Override
public void setX(float x) {
super.setX(x);
Vector2 bodyPos = body.getPosition();
bodyPos.x = x;
body.setTransform(bodyPos, 0);
body.setTransform(pos, 0);
}
@Override
public void setY(float y) {
super.setY(y);
Vector2 bodyPos = body.getPosition();
bodyPos.y = y;
body.setTransform(bodyPos, 0);
body.setTransform(pos, 0);
}
public void setSpeed(float speed) {

View File

@ -1,8 +1,9 @@
package com.me.brickbuster.entity;
import com.badlogic.gdx.graphics.Color;
import com.badlogic.gdx.graphics.g2d.SpriteBatch;
import com.badlogic.gdx.graphics.g2d.TextureRegion;
import com.badlogic.gdx.graphics.glutils.ShapeRenderer;
import com.badlogic.gdx.graphics.glutils.ShapeRenderer.ShapeType;
import com.badlogic.gdx.math.MathUtils;
import com.badlogic.gdx.math.Vector2;
import com.badlogic.gdx.physics.box2d.Body;
import com.badlogic.gdx.physics.box2d.BodyDef;
@ -10,45 +11,42 @@ import com.badlogic.gdx.physics.box2d.FixtureDef;
import com.badlogic.gdx.physics.box2d.PolygonShape;
import com.me.brickbuster.entity.powerup.PowerUpType;
import com.me.brickbuster.physics.CollisionListener;
import com.me.brickbuster.physics.EntityType;
import com.me.brickbuster.physics.PhysicsBody;
import com.me.brickbuster.state.FieldState;
import com.me.brickbuster.state.PlayState;
public class Brick extends Entity implements PhysicsBody, CollisionListener {
public static final Color DEFAULT_COLOR = Color.FOREST;
public static final float BRICK_WIDTH = 5f;
public static final float BRICK_HEIGHT = 2.5f;
public static final float BRICK_WIDTH = 5.2f;
public static final float BRICK_HEIGHT = 2.6f;
private BrickType type;
private BrickShape.Shape shape;
private PowerUpType powerUpType;
private Color color;
private TextureRegion region;
private Body body;
private boolean hitByBall = false;
public Brick(PlayState state, PowerUpType powerUpType, float x, float y) {
this(state, powerUpType, true, x, y);
}
public Brick(PlayState state, PowerUpType powerUpType, boolean hidePowerup, float x, float y) {
this(state, powerUpType, DEFAULT_COLOR, hidePowerup, x, y);
}
public Brick(PlayState state, PowerUpType powerUpType, Color color, boolean hidePowerUp, float x, float y) {
public Brick(FieldState state, BrickType type, BrickShape.Shape shape, PowerUpType powerUpType, float x, float y) {
super(state, x, y);
this.type = type;
this.shape = shape;
this.powerUpType = powerUpType;
this.color = powerUpType != null && !hidePowerUp? powerUpType.getColor() : color;
this.region = state.textures.findRegion("brick_" + shape.name());
createBody();
}
@Override
public void render(ShapeRenderer sr) {
sr.begin(ShapeType.Filled);
sr.setColor(color);
sr.rect(getX() * PlayState.PIXEL_PER_METER,
getY() * PlayState.PIXEL_PER_METER,
BRICK_WIDTH * PlayState.PIXEL_PER_METER,
BRICK_HEIGHT * PlayState.PIXEL_PER_METER);
sr.end();
public void render(SpriteBatch sb, ShapeRenderer sr) {
sb.setColor(type.getColor());
sb.draw(region, pos.x - BRICK_WIDTH/2, pos.y - BRICK_HEIGHT/2,
BRICK_WIDTH/2, BRICK_HEIGHT/2,
BRICK_WIDTH, BRICK_HEIGHT,
1f, 1f,
MathUtils.radiansToDegrees * body.getAngle());
}
@Override
@ -57,6 +55,10 @@ public class Brick extends Entity implements PhysicsBody, CollisionListener {
hit();
hitByBall = false;
}
if (getY() + BRICK_HEIGHT < 0) {
delete();
}
}
@Override
@ -70,13 +72,49 @@ public class Brick extends Entity implements PhysicsBody, CollisionListener {
brickBody.type = BodyDef.BodyType.StaticBody;
brickBody.position.set(pos.cpy());
int shapeMask = shape.getMask();
Vector2[] vertices = new Vector2[Integer.bitCount(shapeMask)];
int v = 0;
if ((shapeMask & BrickShape.BOTTOM_LEFT) != 0) {
vertices[v++] = new Vector2(-BRICK_WIDTH/2, -BRICK_HEIGHT/2);
}
if ((shapeMask & BrickShape.MIDDLE_LEFT) != 0) {
vertices[v++] = new Vector2(-BRICK_WIDTH/2, 0);
}
if ((shapeMask & BrickShape.TOP_LEFT) != 0) {
vertices[v++] = new Vector2(-BRICK_WIDTH/2, BRICK_HEIGHT/2);
}
if ((shapeMask & BrickShape.TOP_MIDDLE) != 0) {
vertices[v++] = new Vector2(0, BRICK_HEIGHT/2);
}
if ((shapeMask & BrickShape.CENTER) != 0) {
vertices[v++] = new Vector2(0, 0);
}
if ((shapeMask & BrickShape.TOP_RIGHT) != 0) {
vertices[v++] = new Vector2(BRICK_WIDTH/2, BRICK_HEIGHT/2);
}
if ((shapeMask & BrickShape.MIDDLE_RIGHT) != 0) {
vertices[v++] = new Vector2(BRICK_WIDTH/2, 0);
}
if ((shapeMask & BrickShape.BOTTOM_RIGHT) != 0) {
vertices[v++] = new Vector2(BRICK_WIDTH/2, -BRICK_HEIGHT/2);
}
if ((shapeMask & BrickShape.BOTTOM_MIDDLE) != 0) {
vertices[v++] = new Vector2(0, -BRICK_HEIGHT/2);
}
PolygonShape brickShape = new PolygonShape();
brickShape.setAsBox(BRICK_WIDTH/2, BRICK_HEIGHT/2,
new Vector2(BRICK_WIDTH/2,BRICK_HEIGHT/2), 0);
brickShape.set(vertices);
FixtureDef brickFixture = new FixtureDef();
brickFixture.shape = brickShape;
brickFixture.friction = 0f;
brickFixture.density = 0.5f;
brickFixture.filter.categoryBits = EntityType.BRICK;
brickFixture.filter.maskBits = EntityType.BALL | EntityType.BRICK | EntityType.BOUNDARY;
body = state.world.createBody(brickBody);
body.createFixture(brickFixture);
@ -96,15 +134,39 @@ public class Brick extends Entity implements PhysicsBody, CollisionListener {
public void endContact(Entity contacted) {
}
@Override
public void setX(float x) {
super.setX(x);
body.setTransform(pos, 0);
}
@Override
public void setY(float y) {
super.setY(y);
body.setTransform(pos, 0);
}
public BrickType getType() {
return type;
}
public BrickShape.Shape getShape() {
return shape;
}
public PowerUpType getPowerUpType() {
return powerUpType;
}
public boolean hit() {
if (state.bricks.size()-1 <= Ball.BLOCKS_FOR_BOOST) {
for (Ball ball : state.balls) {
if (((PlayState) state).bricks.size-1 <= Ball.BLOCKS_FOR_BOOST) {
for (Ball ball : ((PlayState) state).balls) {
ball.setSpeed(Ball.BOOST_SPEED);
}
}
if (powerUpType != null) {
state.powerUps.add(powerUpType.createInstance(state, this));
((PlayState) state).powerUps.add(powerUpType.createInstance((PlayState) state, this));
}
deleted = true;

View File

@ -0,0 +1,84 @@
package com.me.brickbuster.entity;
public class BrickShape {
public static final int BOTTOM_LEFT = 0x1;
public static final int MIDDLE_LEFT = 0x1 << 1;
public static final int TOP_LEFT = 0x1 << 2;
public static final int TOP_MIDDLE = 0x1 << 3;
public static final int CENTER = 0x1 << 4;
public static final int TOP_RIGHT = 0x1 << 5;
public static final int MIDDLE_RIGHT = 0x1 << 6;
public static final int BOTTOM_RIGHT = 0x1 << 7;
public static final int BOTTOM_MIDDLE = 0x1 << 8;
public enum Shape {
RECTANGLE(0, 0, BOTTOM_LEFT | TOP_LEFT | TOP_RIGHT | BOTTOM_RIGHT),
HALF_LEFT_SQUARE(1, 0, BOTTOM_LEFT | TOP_LEFT | TOP_MIDDLE | BOTTOM_MIDDLE),
HALF_RIGHT_SQUARE(2, 0, BOTTOM_MIDDLE | TOP_MIDDLE | TOP_RIGHT | BOTTOM_RIGHT),
HALF_UPPER_RECTANGLE(4, 0, MIDDLE_LEFT | TOP_LEFT | TOP_RIGHT | MIDDLE_RIGHT),
HALF_LOWER_RECTANGLE(5, 0, BOTTOM_LEFT | MIDDLE_LEFT | MIDDLE_RIGHT | BOTTOM_RIGHT),
DIAMOND(2, 1, MIDDLE_LEFT | TOP_MIDDLE | MIDDLE_RIGHT | BOTTOM_MIDDLE),
UP_TRIANGLE(2, 2, BOTTOM_LEFT | TOP_MIDDLE | BOTTOM_RIGHT),
HALF_UP_TRIANGLE(3, 5, BOTTOM_LEFT | CENTER | BOTTOM_RIGHT),
FULL_HALF_UP_TRIANGLE(1, 5, BOTTOM_LEFT | MIDDLE_LEFT | TOP_MIDDLE | MIDDLE_RIGHT | BOTTOM_RIGHT),
DOWN_TRIANGLE(2, 3, TOP_LEFT | TOP_RIGHT | BOTTOM_MIDDLE),
HALF_DOWN_TRIANGLE(2, 5, TOP_LEFT | TOP_RIGHT | CENTER),
FULL_HALF_DOWN_TRIANGLE(0, 5, MIDDLE_LEFT | TOP_LEFT | TOP_RIGHT | MIDDLE_RIGHT | BOTTOM_MIDDLE),
LEFT_TRIANGLE(3, 4, MIDDLE_LEFT | TOP_RIGHT | BOTTOM_RIGHT),
HALF_LEFT_TRIANGLE(2, 4, CENTER | TOP_RIGHT | BOTTOM_RIGHT),
FULL_HALF_LEFT_TRIANGLE(1, 3, MIDDLE_LEFT | TOP_MIDDLE | TOP_RIGHT | BOTTOM_RIGHT | BOTTOM_MIDDLE),
RIGHT_TRIANGLE(0, 4, BOTTOM_LEFT | TOP_LEFT | MIDDLE_RIGHT),
HALF_RIGHT_TRIANGLE(1, 4, BOTTOM_LEFT | TOP_LEFT | CENTER),
FULL_HALF_RIGHT_TRIANGLE(0, 3, BOTTOM_LEFT | TOP_LEFT | TOP_MIDDLE | MIDDLE_RIGHT | BOTTOM_MIDDLE),
DOWN_RIGHT_TRIANGLE(0, 1, BOTTOM_LEFT | TOP_RIGHT | BOTTOM_RIGHT),
LEFT_DOWN_RIGHT_TRIANGLE(0, 6, BOTTOM_LEFT | TOP_MIDDLE | BOTTOM_MIDDLE),
FULL_LEFT_DOWN_RIGHT_TRIANGLE(3, 1, BOTTOM_LEFT | TOP_MIDDLE | TOP_RIGHT | BOTTOM_RIGHT),
RIGHT_DOWN_RIGHT_TRIANGLE(2, 6, BOTTOM_MIDDLE | TOP_RIGHT | BOTTOM_RIGHT),
UP_RIGHT_TRIANGLE(0, 2, TOP_LEFT | TOP_RIGHT | BOTTOM_RIGHT),
LEFT_UP_RIGHT_TRIANGLE(0, 7, TOP_LEFT | TOP_MIDDLE | BOTTOM_MIDDLE),
FULL_LEFT_UP_RIGHT_TRIANGLE(3, 0, TOP_LEFT | TOP_RIGHT | BOTTOM_RIGHT | BOTTOM_MIDDLE),
RIGHT_UP_RIGHT_TRIANGLE(2, 7, TOP_MIDDLE | TOP_RIGHT | BOTTOM_RIGHT),
UP_LEFT_TRIANGLE(1, 2, BOTTOM_LEFT | TOP_LEFT | TOP_RIGHT),
LEFT_UP_LEFT_TRIANGLE(1, 7, BOTTOM_LEFT | TOP_LEFT | TOP_MIDDLE),
FULL_UP_LEFT_TRIANGLE(3, 2, BOTTOM_LEFT | TOP_LEFT | TOP_RIGHT | BOTTOM_MIDDLE),
RIGHT_UP_LEFT_TRIANGLE(3, 7, BOTTOM_MIDDLE | TOP_MIDDLE | TOP_RIGHT),
DOWN_LEFT_TRIANGLE(1, 1, BOTTOM_LEFT | TOP_LEFT | BOTTOM_RIGHT),
LEFT_DOWN_LEFT_TRIANGLE(1, 6, BOTTOM_LEFT | TOP_LEFT | BOTTOM_MIDDLE),
FULL_DOWN_LEFT_TRIANGLE(3, 3, BOTTOM_LEFT | TOP_LEFT | TOP_MIDDLE | BOTTOM_RIGHT),
RIGHT_DOWN_LEFT_TRIANGLE(3, 6, BOTTOM_MIDDLE | TOP_MIDDLE | BOTTOM_RIGHT),
;
private int row;
private int col;
private int mask;
Shape(int row, int col, int mask) {
this.row = row;
this.col = col;
this.mask = mask;
}
public int getRow() {
return row;
}
public int getCol() {
return col;
}
public int getMask() {
return mask;
}
}
}

View File

@ -0,0 +1,31 @@
package com.me.brickbuster.entity;
import com.badlogic.gdx.graphics.Color;
public enum BrickType {
STANDARD_10(new Color(0xf1f1f1ff)),
STANDARD_20(new Color(0xff8f00ff)),
STANDARD_30(Color.CYAN),
STANDARD_40(Color.GREEN),
STANDARD_50(Color.RED),
STANDARD_60(new Color(0x0070ffff)),
STANDARD_70(new Color(0xff00ffff)),
STANDARD_80(new Color(0xffff00ff)),
EXPLOSIVE(Color.GRAY),
HARD(new Color(0x9d9d9dff)),
HARDER(new Color(0xbcae00ff)),
UNBREAKABLE(Color.BLACK)
;
private Color color;
BrickType(Color color) {
this.color = color;
}
public Color getColor() {
return color;
}
}

View File

@ -1,28 +1,31 @@
package com.me.brickbuster.entity;
import com.badlogic.gdx.graphics.g2d.SpriteBatch;
import com.badlogic.gdx.graphics.glutils.ShapeRenderer;
import com.badlogic.gdx.math.Vector2;
import com.me.brickbuster.state.PlayState;
import com.me.brickbuster.state.FieldState;
public abstract class Entity {
protected PlayState state;
protected FieldState state;
protected Vector2 pos;
protected boolean deleted = false;
public Entity(PlayState state, Vector2 pos) {
public Entity(FieldState state, Vector2 pos) {
this(state, pos.x, pos.y);
}
public Entity(PlayState state, float x, float y) {
public Entity(FieldState state, float x, float y) {
this.state = state;
this.pos = new Vector2(x, y);
}
public abstract void render(ShapeRenderer sr);
public abstract void render(SpriteBatch sb, ShapeRenderer sr);
public abstract void update(float dt);
public void dispose() {}
public Vector2 getPos() {
return pos;
}

View File

@ -3,14 +3,17 @@ package com.me.brickbuster.entity;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.Input;
import com.badlogic.gdx.graphics.Color;
import com.badlogic.gdx.graphics.g2d.SpriteBatch;
import com.badlogic.gdx.graphics.glutils.ShapeRenderer;
import com.badlogic.gdx.graphics.glutils.ShapeRenderer.ShapeType;
import com.badlogic.gdx.math.MathUtils;
import com.badlogic.gdx.math.Vector2;
import com.badlogic.gdx.physics.box2d.Body;
import com.badlogic.gdx.physics.box2d.BodyDef;
import com.badlogic.gdx.physics.box2d.EdgeShape;
import com.badlogic.gdx.physics.box2d.FixtureDef;
import com.me.brickbuster.physics.CollisionListener;
import com.me.brickbuster.physics.EntityType;
import com.me.brickbuster.physics.PhysicsBody;
import com.me.brickbuster.state.PlayState;
import net.dermetfan.utils.Pair;
@ -18,7 +21,7 @@ import net.dermetfan.utils.Pair;
public class Paddle extends Entity implements PhysicsBody {
public static final Color STICKY_COLOR = Color.GRAY;
public static final Color PADDLE_COLOR = Color.BLACK;
public static final Color PADDLE_COLOR = Color.WHITE;
public static final float DEFAULT_WIDTH = 7.5f;
public static final float PADDLE_HEIGHT = 0.75f;
@ -36,41 +39,36 @@ public class Paddle extends Entity implements PhysicsBody {
}
@Override
public void render(ShapeRenderer sr) {
public void render(SpriteBatch sb, ShapeRenderer sr) {
sr.begin(ShapeType.Filled);
sr.setColor(sticky? STICKY_COLOR : PADDLE_COLOR);
sr.rect((getX() - width/2) * PlayState.PIXEL_PER_METER,
getY() * PlayState.PIXEL_PER_METER,
width * PlayState.PIXEL_PER_METER,
PADDLE_HEIGHT * PlayState.PIXEL_PER_METER);
sr.rect(pos.x - width/2, pos.y, width, PADDLE_HEIGHT);
sr.end();
}
@Override
public void update(float dt) {
float displacement = PADDLE_SPEED * dt;
float adjust = 0;
if (Gdx.input.isKeyPressed(Input.Keys.LEFT)) {
if (pos.x - width/2 - PADDLE_SPEED * dt < 0) {
setX(width/2);
return;
}
setX(pos.x - PADDLE_SPEED * dt);
for (Ball ball : state.balls) {
if (ball.isStuck()) {
ball.setX(ball.getX() - PADDLE_SPEED * dt);
}
if (pos.x - width / 2 - displacement < PlayState.EDGE_PADDING) {
adjust = -(pos.x - width/2 - PlayState.EDGE_PADDING);
} else {
adjust = -displacement;
}
}
if (Gdx.input.isKeyPressed(Input.Keys.RIGHT)) {
if (pos.x + width/2 + PADDLE_SPEED * dt > PlayState.BOARD_WIDTH) {
setX(PlayState.BOARD_WIDTH - width/2);
return;
if (pos.x + width / 2 + displacement > PlayState.BOARD_WIDTH-PlayState.EDGE_PADDING) {
adjust = PlayState.BOARD_WIDTH - PlayState.EDGE_PADDING - width/2 - pos.x;
} else {
adjust = displacement;
}
setX(pos.x + PADDLE_SPEED * dt);
for (Ball ball : state.balls) {
}
if (!MathUtils.isZero(adjust)) {
setX(pos.x + adjust);
for (Ball ball : ((PlayState) state).balls) {
if (ball.isStuck()) {
ball.setX(ball.getX() + PADDLE_SPEED * dt);
ball.setX(ball.getX() + adjust);
}
}
}
@ -88,7 +86,9 @@ public class Paddle extends Entity implements PhysicsBody {
FixtureDef paddleFixture = new FixtureDef();
paddleFixture.shape = paddleShape;
//paddleFixture.isSensor = true;
paddleFixture.filter.categoryBits = EntityType.PADDLE;
paddleFixture.filter.maskBits = EntityType.BALL | EntityType.POWER_UP;
body = state.world.createBody(paddleBody);
body.createFixture(paddleFixture);
@ -105,17 +105,13 @@ public class Paddle extends Entity implements PhysicsBody {
@Override
public void setX(float x) {
super.setX(x);
Vector2 bodyPos = body.getPosition();
bodyPos.x = x;
body.setTransform(bodyPos, 0);
body.setTransform(pos, 0);
}
@Override
public void setY(float y) {
super.setY(y);
Vector2 bodyPos = body.getPosition();
bodyPos.y = y;
body.setTransform(bodyPos, 0);
body.setTransform(pos, 0);
}
public float getWidth() {
@ -126,7 +122,7 @@ public class Paddle extends Entity implements PhysicsBody {
if (this.width == width) {
return;
}
state.world.destroyBody(body);
((PlayState) state).world.destroyBody(body);
this.width = width;
createBody();
}

View File

@ -1,6 +1,7 @@
package com.me.brickbuster.entity;
import com.badlogic.gdx.graphics.Color;
import com.badlogic.gdx.graphics.g2d.SpriteBatch;
import com.badlogic.gdx.graphics.glutils.ShapeRenderer;
import com.badlogic.gdx.math.Vector2;
import com.badlogic.gdx.physics.box2d.Body;
@ -8,6 +9,7 @@ import com.badlogic.gdx.physics.box2d.BodyDef;
import com.badlogic.gdx.physics.box2d.FixtureDef;
import com.badlogic.gdx.physics.box2d.PolygonShape;
import com.me.brickbuster.entity.powerup.PowerUpType;
import com.me.brickbuster.physics.EntityType;
import com.me.brickbuster.physics.PhysicsBody;
import com.me.brickbuster.state.PlayState;
@ -23,19 +25,17 @@ public class Shield extends Entity implements PhysicsBody {
}
@Override
public void render(ShapeRenderer sr) {
public void render(SpriteBatch sb, ShapeRenderer sr) {
sr.begin(ShapeRenderer.ShapeType.Filled);
sr.setColor(PowerUpType.SHIELD.getColor());
sr.rect(0, pos.y * PlayState.PIXEL_PER_METER,
PlayState.BOARD_WIDTH * PlayState.PIXEL_PER_METER,
SHIELD_HEIGHT * PlayState.PIXEL_PER_METER);
sr.rect(0, pos.y, PlayState.BOARD_WIDTH, SHIELD_HEIGHT);
sr.end();
}
@Override
public void update(float dt) {
if (deleted) {
state.removeShield(this);
((PlayState) state).removeShield(this);
}
}
@ -53,6 +53,9 @@ public class Shield extends Entity implements PhysicsBody {
brickFixture.shape = brickShape;
brickFixture.friction = 0f;
brickFixture.filter.categoryBits = EntityType.SHIELD;
brickFixture.filter.maskBits = EntityType.BALL;
body = state.world.createBody(brickBody);
body.createFixture(brickFixture);
body.setUserData(this);

View File

@ -12,7 +12,7 @@ public class GluePowerUp extends PowerUp {
@Override
public void activate() {
state.paddle.setSticky(true);
((PlayState) state).paddle.setSticky(true);
}
}

View File

@ -13,8 +13,8 @@ public class LongerPaddlePowerUp extends PowerUp {
@Override
public void activate() {
if (state.paddle.getWidth() < Paddle.DEFAULT_WIDTH*2.5) {
state.paddle.setWidth(state.paddle.getWidth() + Paddle.DEFAULT_WIDTH/2);
if (((PlayState) state).paddle.getWidth() < Paddle.DEFAULT_WIDTH*2.5) {
((PlayState) state).paddle.setWidth(((PlayState) state).paddle.getWidth() + Paddle.DEFAULT_WIDTH/2);
}
}
}

View File

@ -19,9 +19,9 @@ public class MultiBallPowerUp extends PowerUp {
@Override
public void activate() {
for (int x = 0; x < 2; x++) {
Ball ball = new Ball(state);
Ball ball = new Ball((PlayState) state);
ball.launch();
state.balls.add(ball);
((PlayState) state).balls.add(ball);
}
}
}

View File

@ -1,6 +1,7 @@
package com.me.brickbuster.entity.powerup;
import com.badlogic.gdx.graphics.Color;
import com.badlogic.gdx.graphics.g2d.SpriteBatch;
import com.badlogic.gdx.graphics.glutils.ShapeRenderer;
import com.badlogic.gdx.graphics.glutils.ShapeRenderer.ShapeType;
import com.badlogic.gdx.math.Vector2;
@ -8,13 +9,13 @@ import com.badlogic.gdx.physics.box2d.Body;
import com.badlogic.gdx.physics.box2d.BodyDef;
import com.badlogic.gdx.physics.box2d.CircleShape;
import com.badlogic.gdx.physics.box2d.FixtureDef;
import com.me.brickbuster.Utils;
import com.me.brickbuster.entity.Ball;
import com.me.brickbuster.entity.Entity;
import com.me.brickbuster.entity.Paddle;
import com.me.brickbuster.physics.CollisionListener;
import com.me.brickbuster.physics.EntityType;
import com.me.brickbuster.physics.PhysicsBody;
import com.me.brickbuster.state.PlayState;
import net.dermetfan.utils.Pair;
public abstract class PowerUp extends Entity implements PhysicsBody, CollisionListener {
@ -33,12 +34,10 @@ public abstract class PowerUp extends Entity implements PhysicsBody, CollisionLi
}
@Override
public void render(ShapeRenderer sr) {
public void render(SpriteBatch sb, ShapeRenderer sr) {
sr.begin(ShapeType.Filled);
sr.setColor(color);
sr.circle(getX() * PlayState.PIXEL_PER_METER,
getY() * PlayState.PIXEL_PER_METER,
RADIUS * PlayState.PIXEL_PER_METER);
sr.circle(pos.x, pos.y, RADIUS, 20);
sr.end();
}
@ -72,6 +71,9 @@ public abstract class PowerUp extends Entity implements PhysicsBody, CollisionLi
ballFixture.shape = ballShape;
ballFixture.isSensor = true;
ballFixture.filter.categoryBits = EntityType.POWER_UP;
ballFixture.filter.maskBits = EntityType.PADDLE;
body = state.world.createBody(ballBody);
body.createFixture(ballFixture);
body.setUserData(this);
@ -83,7 +85,7 @@ public abstract class PowerUp extends Entity implements PhysicsBody, CollisionLi
@Override
public void beginContact(Entity contacted) {
if (contacted instanceof Paddle) {
if (contacted instanceof Paddle || contacted instanceof Ball) {
isCaught = true;
}
}

View File

@ -42,9 +42,7 @@ public enum PowerUpType {
}
public PowerUp createInstance(PlayState state, Brick brick) {
return createInstance(state,
new Vector2(brick.getX()+Brick.BRICK_WIDTH/2,
brick.getY()+Brick.BRICK_HEIGHT/2));
return createInstance(state, new Vector2(brick.getX(), brick.getY()));
}
public PowerUp createInstance(PlayState state, Vector2 pos) {

View File

@ -12,7 +12,7 @@ public class ShieldPowerUp extends PowerUp {
@Override
public void activate() {
state.addShield();
((PlayState) state).addShield();
}
}

View File

@ -0,0 +1,12 @@
package com.me.brickbuster.layout;
import com.badlogic.gdx.utils.Array;
import com.me.brickbuster.entity.Brick;
public interface BrickLayout {
void initialize();
Array<Brick> getBricks();
}

View File

@ -0,0 +1,41 @@
package com.me.brickbuster.layout;
import com.badlogic.gdx.files.FileHandle;
import com.badlogic.gdx.utils.Array;
import com.badlogic.gdx.utils.Json;
import com.me.brickbuster.entity.Brick;
import com.me.brickbuster.state.PlayState;
public class FileLayout implements BrickLayout {
private static final Json JSON = new Json();
private PlayState state;
private Array<Brick> bricks;
private FileHandle file;
public FileLayout(PlayState state, FileHandle file) {
this.state = state;
this.file = file;
}
@Override
public void initialize() {
bricks = new Array<Brick>();
LevelJsonTemplate level = JSON.fromJson(LevelJsonTemplate.class, file);
for (LevelJsonTemplate.BrickJsonTemplate brick : level.bricks) {
final float x = PlayState.EDGE_PADDING + Brick.BRICK_WIDTH/2 + brick.col * Brick.BRICK_WIDTH;
final float y = PlayState.EDGE_PADDING + Brick.BRICK_HEIGHT/2 + brick.row * Brick.BRICK_HEIGHT;
bricks.add(new Brick(state, brick.type, brick.shape, brick.powerUp, x, PlayState.BOARD_HEIGHT - y));
}
}
@Override
public Array<Brick> getBricks() {
return bricks;
}
}

View File

@ -0,0 +1,26 @@
package com.me.brickbuster.layout;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.files.FileHandle;
import com.me.brickbuster.state.PlayState;
public class FileLevelLoader implements LevelLoader {
private PlayState state;
private int level = 1;
public FileLevelLoader(PlayState state) {
this.state = state;
}
@Override
public Level getNextLevel() {
FileHandle file = Gdx.files.internal("levels/level_" + level + ".json");
if (file.exists()) {
level++;
return new Level(new FileLayout(state, file), null, null);
}
return null;
}
}

View File

@ -0,0 +1,80 @@
package com.me.brickbuster.layout;
import com.badlogic.gdx.math.MathUtils;
import com.badlogic.gdx.utils.Array;
import com.me.brickbuster.entity.Brick;
import com.me.brickbuster.entity.BrickShape;
import com.me.brickbuster.entity.BrickType;
import com.me.brickbuster.entity.powerup.PowerUpType;
import com.me.brickbuster.state.PlayState;
public class GridLayout implements BrickLayout {
private final PlayState state;
private final int cols;
private final int rows;
private final float powerUpChance;
private BrickShape.Shape shape = null;
private BrickType type = null;
private boolean randomShape = false;
private boolean randomType = false;
private final Array<Brick> bricks;
public GridLayout(PlayState state, int cols, int rows, float powerUpChance) {
this(state, cols, rows, powerUpChance, false, false);
}
public GridLayout(PlayState state, int cols, int rows, float powerUpChance, boolean randomShape, boolean randomType) {
this(state, cols, rows, powerUpChance, BrickShape.Shape.RECTANGLE, BrickType.STANDARD_10);
this.randomShape = randomShape;
this.randomType = randomType;
}
public GridLayout(PlayState state, int cols, int rows, float powerUpChance, BrickShape.Shape shape, BrickType type) {
this.state = state;
this.cols = cols;
this.rows = rows;
this.powerUpChance = powerUpChance;
this.shape = shape;
this.type = type;
this.bricks = new Array<Brick>(cols * rows);
}
@Override
public void initialize() {
for (int col = 0; col < cols; col++) {
for (int row = 0; row < rows; row++) {
bricks.add(getBrickForCell(row, col));
}
}
}
protected Brick getBrickForCell(int row, int col) {
final float x = PlayState.EDGE_PADDING + Brick.BRICK_WIDTH/2 + col * Brick.BRICK_WIDTH;
final float y = PlayState.EDGE_PADDING + Brick.BRICK_HEIGHT/2 + row * Brick.BRICK_HEIGHT;
PowerUpType powerUpType = null;
if (MathUtils.randomBoolean(powerUpChance)) {
powerUpType = PowerUpType.getWeightedRandom();
}
if (randomType) {
type = BrickType.values()[MathUtils.random(BrickType.values().length-1)];
}
if (randomShape) {
shape = BrickShape.Shape.values()[MathUtils.random(BrickShape.Shape.values().length-1)];
}
return new Brick(state, type, shape, powerUpType, x, PlayState.BOARD_HEIGHT - y);
}
@Override
public Array<Brick> getBricks() {
return bricks;
}
}

View File

@ -0,0 +1,35 @@
package com.me.brickbuster.layout;
import com.me.brickbuster.state.PlayState;
public class GridLevelLoader implements LevelLoader {
public static final float POWER_UP_CHANCE = 0.15f;
public static final int COLUMNS = 10;
public static final int ROWS = 20;
public static final int ROUNDS = 2;
private PlayState state;
private boolean randomShape;
private boolean randomType;
private int playCount = 0;
public GridLevelLoader(PlayState state) {
this(state, false, false);
}
public GridLevelLoader(PlayState state, boolean randomShape, boolean randomType) {
this.state = state;
this.randomShape = randomShape;
this.randomType = randomType;
}
@Override
public Level getNextLevel() {
if (playCount++ < ROUNDS) {
return new Level(new GridLayout(state, COLUMNS, ROWS, POWER_UP_CHANCE, randomShape, randomType));
}
return null;
}
}

View File

@ -0,0 +1,33 @@
package com.me.brickbuster.layout;
import com.badlogic.gdx.graphics.Texture;
public class Level {
private final BrickLayout layout;
private final Texture background;
private final Texture border;
public Level(BrickLayout layout) {
this(layout, null, null);
}
public Level(BrickLayout layout, Texture background, Texture border) {
this.layout = layout;
this.background = background;
this.border = border;
}
public BrickLayout getLayout() {
return layout;
}
public Texture getBackground() {
return background;
}
public Texture getBorder() {
return border;
}
}

View File

@ -0,0 +1,23 @@
package com.me.brickbuster.layout;
import com.me.brickbuster.entity.BrickShape;
import com.me.brickbuster.entity.BrickType;
import com.me.brickbuster.entity.powerup.PowerUpType;
import java.util.List;
public class LevelJsonTemplate {
public String backgroundFile;
public String borderFile;
public List<BrickJsonTemplate> bricks;
public static class BrickJsonTemplate {
public int col;
public int row;
public BrickType type;
public BrickShape.Shape shape;
public PowerUpType powerUp;
}
}

View File

@ -0,0 +1,7 @@
package com.me.brickbuster.layout;
public interface LevelLoader {
Level getNextLevel();
}

View File

@ -0,0 +1,12 @@
package com.me.brickbuster.physics;
public final class EntityType {
public static final short BOUNDARY = 0x1;
public static final short BALL = 0x1 << 1;
public static final short BRICK = 0x1 << 2;
public static final short PADDLE = 0x1 << 3;
public static final short POWER_UP = 0x1 << 4;
public static final short SHIELD = 0x1 << 5;
}

View File

@ -0,0 +1,233 @@
package com.me.brickbuster.state;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.Input;
import com.badlogic.gdx.InputAdapter;
import com.badlogic.gdx.files.FileHandle;
import com.badlogic.gdx.graphics.Color;
import com.badlogic.gdx.math.Vector2;
import com.badlogic.gdx.physics.box2d.Box2DDebugRenderer;
import com.badlogic.gdx.physics.box2d.World;
import com.badlogic.gdx.utils.Json;
import com.me.brickbuster.BrickBuster;
import com.me.brickbuster.entity.Brick;
import com.me.brickbuster.entity.BrickShape;
import com.me.brickbuster.entity.BrickType;
import com.me.brickbuster.entity.powerup.PowerUpType;
import com.me.brickbuster.layout.LevelJsonTemplate;
import com.me.brickbuster.physics.Box2dContactListener;
import java.util.ArrayList;
public class EditorState extends FieldState {
public static final long BLINK_INTERVAL = 250l;
public static final int COLUMNS = 10;
public static final int ROWS = 33;
private Brick placeHolder;
private Brick[][] bricks = new Brick[COLUMNS][ROWS];
private int col = 0;
private int row = 0;
private PowerUpType curPowerUpType;
private BrickShape.Shape curShape;
private BrickType curType;
private Box2DDebugRenderer debugRenderer;
private long lastBlink = System.currentTimeMillis();
private boolean blink = false;
public EditorState(BrickBuster game) {
super(game);
}
@Override
public void setup() {
super.setup();
world = new World(new Vector2(), false);
world.setContactListener(new Box2dContactListener());
curPowerUpType = null;
curShape = BrickShape.Shape.RECTANGLE;
curType = BrickType.STANDARD_10;
updatePlaceHolder();
Gdx.input.setInputProcessor(new InputProcessor());
debugRenderer = new Box2DDebugRenderer();
}
@Override
public void render() {
game.sb.begin();
for (int col = 0; col < bricks.length; col++) {
for (int row = 0; row < bricks[col].length; row++) {
if (col == this.col && row == this.row && !blink) {
continue;
}
Brick brick = bricks[col][row];
if (brick != null) {
brick.render(game.sb, game.sr);
}
}
}
if (!blink) {
placeHolder.render(game.sb, game.sr);
}
game.sb.end();
debugRenderer.render(world, game.cam.combined.cpy().scl(PlayState.PIXEL_PER_METER));
game.fb.begin();
game.font.setColor(Color.GRAY);
game.font.draw(game.fb, String.format("Current powerup: %s", curPowerUpType), 10, 230);
game.font.draw(game.fb, "WASD: Move brick", 10, 170);
game.font.draw(game.fb, "ENTER: Set brick BACKSPACE: Delete brick F12: Save", 10, 110);
game.font.draw(game.fb, "UP/DOWN: type LEFT/RIGHT: shape SPACE: powerup", 10, 55);
game.fb.end();
}
@Override
public void update(float dt) {
long now = System.currentTimeMillis();
if (now - lastBlink > BLINK_INTERVAL) {
blink = !blink;
lastBlink = now;
}
}
private void updatePlaceHolder() {
if (placeHolder != null) {
world.destroyBody(placeHolder.getBody());
}
placeHolder = createBrick();
}
private Brick createBrick() {
return new Brick(this, curType, curShape, curPowerUpType, getBrickX(), getBrickY());
}
private float getBrickX() {
return PlayState.EDGE_PADDING + Brick.BRICK_WIDTH/2 + col * Brick.BRICK_WIDTH;
}
private float getBrickY() {
return PlayState.BOARD_HEIGHT - (PlayState.EDGE_PADDING + Brick.BRICK_HEIGHT/2 + row * Brick.BRICK_HEIGHT);
}
private void saveToFile() {
Json json = new Json();
FileHandle file = Gdx.files.external("level.json");
LevelJsonTemplate level = new LevelJsonTemplate();
level.bricks = new ArrayList<LevelJsonTemplate.BrickJsonTemplate>();
for (int col = 0; col < bricks.length; col++) {
for (int row = 0; row < bricks[col].length; row++) {
Brick brick = bricks[col][row];
if (brick == null) {
continue;
}
LevelJsonTemplate.BrickJsonTemplate brickJson = new LevelJsonTemplate.BrickJsonTemplate();
brickJson.col = col;
brickJson.row = row;
brickJson.type = brick.getType();
brickJson.shape = brick.getShape();
brickJson.powerUp = brick.getPowerUpType();
level.bricks.add(brickJson);
}
}
file.writeString(json.prettyPrint(level), false);
System.out.println("level.json saved to " + file.file().getAbsolutePath());
}
private final class InputProcessor extends InputAdapter {
@Override
public boolean keyDown(int keycode) {
int next = -1;
switch (keycode) {
case Input.Keys.UP:
next = curType.ordinal() == BrickType.values().length-1? 0 : curType.ordinal()+1;
curType = BrickType.values()[next];
updatePlaceHolder();
break;
case Input.Keys.DOWN:
next = curType.ordinal() == 0? BrickType.values().length-1 : curType.ordinal()-1;
curType = BrickType.values()[next];
updatePlaceHolder();
break;
case Input.Keys.LEFT:
next = curShape.ordinal() == 0? BrickShape.Shape.values().length-1 : curShape.ordinal()-1;
curShape = BrickShape.Shape.values()[next];
updatePlaceHolder();
break;
case Input.Keys.RIGHT:
next = curShape.ordinal() == BrickShape.Shape.values().length-1? 0 : curShape.ordinal()+1;
curShape = BrickShape.Shape.values()[next];
updatePlaceHolder();
break;
case Input.Keys.W:
if (row > 0) {
row--;
placeHolder.setY(getBrickY());
}
break;
case Input.Keys.A:
if (col > 0) {
col--;
placeHolder.setX(getBrickX());
}
break;
case Input.Keys.S:
if (row < ROWS-1) {
row++;
placeHolder.setY(getBrickY());
}
break;
case Input.Keys.D:
if (col < COLUMNS-1) {
col++;
placeHolder.setX(getBrickX());
}
break;
case Input.Keys.SPACE:
next = curPowerUpType == null? 0 : curPowerUpType.ordinal()+1;
if (next >= curPowerUpType.values().length) {
curPowerUpType = null;
} else {
curPowerUpType = PowerUpType.values()[next];
}
break;
case Input.Keys.ENTER:
if (bricks[col][row] != null) {
world.destroyBody(bricks[col][row].getBody());
bricks[col][row].dispose();
}
bricks[col][row] = createBrick();
break;
case Input.Keys.BACKSPACE:
if (bricks[col][row] != null) {
world.destroyBody(bricks[col][row].getBody());
bricks[col][row].dispose();
bricks[col][row] = null;
}
break;
case Input.Keys.F12:
saveToFile();
break;
default:
return false;
}
return true;
}
}
}

View File

@ -0,0 +1,30 @@
package com.me.brickbuster.state;
import com.badlogic.gdx.graphics.g2d.TextureAtlas;
import com.badlogic.gdx.physics.box2d.World;
import com.me.brickbuster.BrickBuster;
public abstract class FieldState extends State {
public World world;
public TextureAtlas textures;
public FieldState(BrickBuster game) {
super(game);
}
@Override
public void setup() {
game.assets.load("textures.atlas", TextureAtlas.class);
game.assets.finishLoading();
textures = game.assets.get("textures.atlas", TextureAtlas.class);
}
@Override
public void dispose() {
super.dispose();
textures.dispose();
}
}

View File

@ -1,6 +1,7 @@
package com.me.brickbuster.state;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.Input;
import com.badlogic.gdx.graphics.Texture;
import com.badlogic.gdx.math.Vector3;
import com.me.brickbuster.BrickBuster;
@ -20,11 +21,13 @@ public class MenuState extends State {
@Override
public void render() {
game.sb.setProjectionMatrix(game.cam.combined);
game.sb.begin();
game.sb.draw(playButton,
BrickBuster.BOARD_WIDTH/2-playButton.getWidth()/2,
BrickBuster.BOARD_HEIGHT/2-playButton.getHeight()/2);
game.sb.end();
game.sb.setProjectionMatrix(game.cam.combined.cpy().scl(PlayState.PIXEL_PER_METER));
}
@Override
@ -39,6 +42,11 @@ public class MenuState extends State {
dispose();
}
}
if(Gdx.input.isKeyJustPressed(Input.Keys.F12)) {
game.setScreen(new EditorState(game));
dispose();
}
}
@Override

View File

@ -2,51 +2,50 @@ package com.me.brickbuster.state;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.graphics.Color;
import com.badlogic.gdx.math.MathUtils;
import com.badlogic.gdx.math.Vector2;
import com.badlogic.gdx.physics.box2d.*;
import com.badlogic.gdx.utils.Array;
import com.me.brickbuster.BrickBuster;
import com.me.brickbuster.utils.CompositeIterator;
import com.me.brickbuster.entity.*;
import com.me.brickbuster.entity.powerup.PowerUp;
import com.me.brickbuster.entity.powerup.PowerUpType;
import com.me.brickbuster.layout.BrickLayout;
import com.me.brickbuster.layout.FileLevelLoader;
import com.me.brickbuster.layout.Level;
import com.me.brickbuster.layout.LevelLoader;
import com.me.brickbuster.physics.Box2dContactListener;
import com.me.brickbuster.physics.EntityType;
import com.me.brickbuster.physics.PhysicsBody;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
public class PlayState extends State {
public class PlayState extends FieldState {
public static final float PIXEL_PER_METER = 40f; // Board dimension: 54x96 meters
public static final float BOARD_WIDTH = 54f;
public static final float BOARD_HEIGHT = 96f;
public static final float EDGE_PADDING = .125f;
public static final float POWERUP_CHANCE = 0.15f;
public static final int COLUMNS = 9;
public static final int ROWS = 8;
public static final float PIXEL_PER_METER = BrickBuster.BOARD_WIDTH / BOARD_WIDTH;
public static final float EDGE_PADDING = 1f;
public static final Vector2 lowerLeftCorner =
new Vector2(EDGE_PADDING,EDGE_PADDING);
new Vector2(EDGE_PADDING,0);
public static final Vector2 lowerRightCorner =
new Vector2(BrickBuster.BOARD_WIDTH/PIXEL_PER_METER-EDGE_PADDING,EDGE_PADDING);
new Vector2(BrickBuster.BOARD_WIDTH/PIXEL_PER_METER-EDGE_PADDING,0);
public static final Vector2 upperRightCorner =
new Vector2(BrickBuster.BOARD_WIDTH/PIXEL_PER_METER-EDGE_PADDING, BrickBuster.BOARD_HEIGHT/PIXEL_PER_METER-EDGE_PADDING);
public static final Vector2 upperLeftCorner =
new Vector2(EDGE_PADDING, BrickBuster.BOARD_HEIGHT/PIXEL_PER_METER-EDGE_PADDING);
public World world;
public Body playArea;
public Array<Body> bodies;
public List<PowerUp> powerUps;
public LevelLoader levelLoader;
public Level currentLevel;
public Array<PowerUp> powerUps;
public Paddle paddle;
public List<Ball> balls;
public List<Brick> bricks;
public List<Shield> shields;
public Array<Ball> balls;
public Array<Brick> bricks;
public Array<Shield> shields;
private float updateTime = 0f;
@ -59,142 +58,86 @@ public class PlayState extends State {
@Override
public void setup() {
super.setup();
// Initialize a world with no gravity
world = new World(new Vector2(), false);
world.setContactListener(new Box2dContactListener());
bodies = new Array<Body>();
// define a playArea body with position set to 0
BodyDef playAreaDef = new BodyDef();
playAreaDef.type = BodyDef.BodyType.StaticBody;
playAreaDef.position.set(new Vector2());
levelLoader = new FileLevelLoader(this);
currentLevel = levelLoader.getNextLevel();
EdgeShape screenEdge = new EdgeShape();
playArea = world.createBody(playAreaDef);
// Right edge
screenEdge.set(lowerRightCorner, upperRightCorner);
playArea.createFixture(screenEdge, 0f);
// Top edge
screenEdge.set(upperRightCorner, upperLeftCorner);
playArea.createFixture(screenEdge, 0f);
// Left edge
screenEdge.set(upperLeftCorner, lowerLeftCorner);
playArea.createFixture(screenEdge, 0f);
// Bottom edge
//screenEdge.set(lowerLeftCorner, lowerRightCorner);
//playArea.createFixture(screenEdge, 0f);
screenEdge.dispose();
powerUps = new ArrayList<PowerUp>();
paddle = new Paddle(this);
float brick_padding = ((BrickBuster.BOARD_WIDTH/PIXEL_PER_METER) - COLUMNS * Brick.BRICK_WIDTH) / (COLUMNS + 1);
bricks = new ArrayList<Brick>();
for (int col = 0; col < COLUMNS; col++) {
for (int row = 0; row < ROWS; row++) {
float x = brick_padding + (col * (Brick.BRICK_WIDTH + brick_padding));
float y = brick_padding + Brick.BRICK_HEIGHT + (row * (Brick.BRICK_HEIGHT + brick_padding));
PowerUpType powerUpType = null;
if (MathUtils.randomBoolean(POWERUP_CHANCE)) {
powerUpType = PowerUpType.getWeightedRandom();
}
bricks.add(new Brick(this, powerUpType, x, BrickBuster.BOARD_HEIGHT/PIXEL_PER_METER - y));
}
}
balls = new ArrayList<Ball>();
balls.add(new Ball(this));
shields = new ArrayList<Shield>();
initializeLevel();
}
@Override
public void render() {
Array<Body> bodies = new Array<Body>();
world.getBodies(bodies);
for (Body b : bodies) {
Entity e = (Entity) b.getUserData();
if (e instanceof Ball || e instanceof PowerUp) {
if (e instanceof Ball || e instanceof PowerUp || e instanceof Brick) {
e.setPos(b.getPosition());
}
}
long start = System.nanoTime();
for (Brick block : bricks) {
block.render(game.sr);
game.sb.begin();
Iterator<? extends Entity> it = CompositeIterator.concat(balls, bricks);
while (it.hasNext()) {
it.next().render(game.sb, game.sr);
}
for (PowerUp powerUp : powerUps) {
powerUp.render(game.sr);
game.sb.end();
it = CompositeIterator.concat(powerUps, shields);
while (it.hasNext()) {
it.next().render(game.sb, game.sr);
}
for (Ball ball : balls) {
ball.render(game.sr);
}
for (Shield shield : shields) {
shield.render(game.sr);
}
paddle.render(game.sr);
paddle.render(game.sb, game.sr);
//debugRenderer.render(world, game.cam.combined.cpy().scl(PIXEL_PER_METER));
long renderTime = System.nanoTime() - start;
game.sb.begin();
game.fb.begin();
game.font.setColor(Color.GRAY);
game.font.draw(game.sb, String.format("FPS: %d Update: %.2f ms Render: %.2f ms",
game.font.draw(game.fb, String.format("FPS: %d Update: %.2f ms Render: %.2f ms",
Gdx.graphics.getFramesPerSecond(), updateTime/1000000f, renderTime/1000000f), 10, BrickBuster.BOARD_HEIGHT-10);
game.sb.end();
game.fb.end();
}
@Override
public void update(float dt) {
long start = System.nanoTime();
paddle.update(dt);
for (Iterator<Ball> it = balls.iterator(); it.hasNext();) {
Ball ball = it.next();
ball.update(dt);
if (ball.isDeleted()) {
Iterator<? extends Entity> it = CompositeIterator.concat(balls, powerUps, shields, bricks);
while (it.hasNext()) {
Entity ent = it.next();
ent.update(dt);
if (ent.isDeleted()) {
it.remove();
world.destroyBody(ball.getBody());
if (ent instanceof PhysicsBody) {
world.destroyBody(((PhysicsBody) ent).getBody());
}
ent.dispose();
}
}
if (balls.isEmpty()) {
if (balls.size == 0) {
ballReset();
}
for (Iterator<PowerUp> it = powerUps.iterator(); it.hasNext();) {
PowerUp powerUp = it.next();
powerUp.update(dt);
if(powerUp.isDeleted()) {
it.remove();
world.destroyBody(powerUp.getBody());
if (bricks.size == 0) {
currentLevel = levelLoader.getNextLevel();
if (currentLevel == null) {
game.setScreen(new MenuState(game));
dispose();
} else {
initializeLevel();
}
}
for (Iterator<Shield> it = shields.iterator(); it.hasNext();) {
Shield shield = it.next();
shield.update(dt);
if(shield.isDeleted()) {
it.remove();
world.destroyBody(shield.getBody());
}
}
for (Iterator<Brick> it = bricks.iterator(); it.hasNext();) {
Brick brick = it.next();
brick.update(dt);
if (brick.isDeleted()) {
it.remove();
world.destroyBody(brick.getBody());
}
}
if (bricks.isEmpty()) {
game.setScreen(new MenuState(game));
dispose();
return;
}
world.step(dt, 6, 2);
updateTime = System.nanoTime() - start;
}
@ -202,9 +145,10 @@ public class PlayState extends State {
@Override
public void dispose() {
super.dispose();
world.dispose();
bodies.clear();
powerUps.clear();
powerUps = null;
balls.clear();
@ -214,8 +158,48 @@ public class PlayState extends State {
paddle = null;
}
private void initializeLevel() {
world.getBodies(bodies);
for (Body b : bodies) {
world.destroyBody(b);
}
// Set up the borders
BodyDef playAreaDef = new BodyDef();
playAreaDef.type = BodyDef.BodyType.StaticBody;
playAreaDef.position.set(new Vector2());
EdgeShape screenEdge = new EdgeShape();
FixtureDef playAreaFixture = new FixtureDef();
playAreaFixture.shape = screenEdge;
playAreaFixture.filter.categoryBits = EntityType.BOUNDARY;
playAreaFixture.filter.maskBits = EntityType.BALL | EntityType.BRICK;
playArea = world.createBody(playAreaDef);
screenEdge.set(lowerRightCorner, upperRightCorner);
playArea.createFixture(playAreaFixture);
screenEdge.set(upperRightCorner, upperLeftCorner);
playArea.createFixture(playAreaFixture);
screenEdge.set(upperLeftCorner, lowerLeftCorner);
playArea.createFixture(playAreaFixture);
screenEdge.dispose();
powerUps = new Array<PowerUp>();
paddle = new Paddle(this);
BrickLayout layout = currentLevel.getLayout();
layout.initialize();
bricks = layout.getBricks();
balls = new Array<Ball>();
balls.add(new Ball(this));
shields = new Array<Shield>();
}
public int getShieldCount() {
return shields.size();
return shields.size;
}
public void addShield() {

View File

@ -26,6 +26,10 @@ public abstract class State extends ScreenAdapter {
this.disposed = true;
}
public BrickBuster getGame() {
return game;
}
public abstract void setup();
public abstract void render();

View File

@ -0,0 +1,43 @@
package com.me.brickbuster.utils;
import java.util.Iterator;
public class CompositeIterator<T> implements Iterator<T> {
private short index = 0;
private Iterator<? extends T> iterator;
private Iterable<? extends T>[] iterables;
private CompositeIterator(Iterable<? extends T>... iterables) {
this.iterables = iterables;
this.iterator = iterables[index].iterator();
}
@Override
public boolean hasNext() {
if (iterator.hasNext()) {
return true;
} else {
if (++index < iterables.length) {
iterator = iterables[index].iterator();
return hasNext();
}
}
return false;
}
@Override
public T next() {
return iterator.next();
}
@Override
public void remove() {
iterator.remove();
}
public static <E> CompositeIterator<E> concat(Iterable<? extends E>... iterables) {
return new CompositeIterator<E>(iterables);
}
}

View File

@ -1,4 +1,4 @@
package com.me.brickbuster;
package com.me.brickbuster.utils;
import com.badlogic.gdx.math.MathUtils;
import com.badlogic.gdx.math.Vector2;

View File

@ -7,12 +7,9 @@ import com.me.brickbuster.BrickBuster;
public class DesktopLauncher {
public static void main (String[] arg) {
LwjglApplicationConfiguration config = new LwjglApplicationConfiguration();
config.width = 450;
config.height = 800;
config.width = 432;
config.height = 768;
config.title = BrickBuster.TITLE;
//config.vSyncEnabled = false;
//config.foregroundFPS = 0;
new LwjglApplication(new BrickBuster(), config);
}
}

View File

@ -0,0 +1,17 @@
package com.me.brickbuster.desktop;
import com.badlogic.gdx.graphics.Texture;
import com.badlogic.gdx.tools.texturepacker.TexturePacker;
public class TextureSetup {
public static void main(String[] args) {
TexturePacker.Settings settings = new TexturePacker.Settings();
settings.paddingX = 8;
settings.paddingY = 8;
settings.filterMin = Texture.TextureFilter.MipMapLinearLinear;
settings.filterMag = Texture.TextureFilter.MipMapLinearLinear;
TexturePacker.process(settings,"sprites", "./", "textures");
}
}