add animated water ripple tile and a trap trigger

This commit is contained in:
Quillraven
2025-06-01 21:46:14 +02:00
parent d5cd88a245
commit 7cf6dbe9e4
28 changed files with 445 additions and 167 deletions

View File

@@ -2,3 +2,4 @@ https://kenmi-art.itch.io/cute-fantasy-rpg
https://yubatake.bandcamp.com/album/jrpg-collection https://yubatake.bandcamp.com/album/jrpg-collection
https://crusenho.itch.io/complete-ui-essential-pack https://crusenho.itch.io/complete-ui-essential-pack
https://xdeviruchi.itch.io/8-bit-fantasy-adventure-music-pack https://xdeviruchi.itch.io/8-bit-fantasy-adventure-music-pack
https://sfxr.me/

BIN
assets/audio/trap.wav Normal file

Binary file not shown.

View File

@@ -361,3 +361,17 @@ player/walk_up
orig: 32, 32 orig: 32, 32
offset: 0, 0 offset: 0, 0
index: 5 index: 5
trap/idle_down
rotate: false
xy: 38, 13
size: 16, 16
orig: 16, 16
offset: 0, 0
index: 0
trap/idle_down
rotate: false
xy: 410, 129
size: 16, 16
orig: 16, 16
offset: 0, 0
index: 1

Binary file not shown.

Before

Width:  |  Height:  |  Size: 14 KiB

After

Width:  |  Height:  |  Size: 15 KiB

View File

@@ -1,21 +1,27 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<map version="1.10" tiledversion="1.11.0" orientation="orthogonal" renderorder="right-down" width="18" height="16" tilewidth="16" tileheight="16" infinite="0" nextlayerid="7" nextobjectid="15"> <map version="1.10" tiledversion="1.11.0" orientation="orthogonal" renderorder="right-down" width="18" height="16" tilewidth="16" tileheight="16" infinite="0" nextlayerid="7" nextobjectid="17">
<properties> <properties>
<property name="music" value="TOWN"/> <property name="music" value="TOWN"/>
</properties> </properties>
<tileset firstgid="1" source="objects.tsx"/> <tileset firstgid="1" source="objects.tsx"/>
<tileset firstgid="7" source="tileset.tsx"/> <tileset firstgid="8" source="tileset.tsx"/>
<layer id="1" name="ground" width="18" height="16"> <layer id="1" name="ground" width="18" height="16">
<data encoding="base64" compression="zlib"> <data encoding="base64" compression="zlib">
eJylkjsPwjAMhLPykCoeEjDBxkgzARPqBEywla2w9lfkp3OVYumwTAgwfFIb+c7xOcE5twRzgxUIXzAyzkpQxO8t2Cn2hmYNesZ5ET1uoCXuoIo1G0PD/92sC3CI2gs4EWejb+c5i3l48gjkUxm6XHgm9vGZWslSPBpQOztbQe9BZ8rURr0g/bheMr0mPHl3rXvdAe/CU8ZWD00qK/F5kM8vezvG2fgO1rvJ9WJt+aFev+9/6YOBYvimNnW3MZgophn9n9wdbaQ= eJylkjsOwjAQRF3z6SI+HVBDzwGIa6BGqYEa+tAHLpCz+G5MJK80Wm2MgeJJibUz6511cM6twdJgA8IXTIyzEhTxew8OiqOh2YKBcV5EjwdoiSeoYs3O0PB/N+sKnKL2Bi7E1ejbeS5iHp48AvlUhi4Xnol9fKZWshSPBtQ92Qp6DzpTpjbqBenH9ZLpPeHJu2vVDngXnjK2emhSWYnPi3x+2ds5zsZ3sN5Nrhdryw/1+n3/yxCMFOOe2tTdpmCmmGf0fwPl7aDo
</data> </data>
</layer> </layer>
<layer id="3" name="water" width="18" height="16"> <layer id="3" name="water" width="18" height="16">
<data encoding="base64" compression="zlib"> <data encoding="base64" compression="zlib">
eJxjYBgFo2AUjALKgTES24hIPQAWrABm eJxjYBgFo2AUjALKgQcQC0DZ7kTqAQAhOACg
</data> </data>
</layer> </layer>
<objectgroup id="6" name="trigger"/> <objectgroup id="6" name="trigger">
<object id="16" name="trap_trigger" x="97" y="114" width="14" height="12">
<properties>
<property name="sensor" type="bool" value="true"/>
</properties>
</object>
</objectgroup>
<objectgroup id="5" name="objects"> <objectgroup id="5" name="objects">
<object id="5" gid="3" x="197" y="118" width="80" height="112"/> <object id="5" gid="3" x="197" y="118" width="80" height="112"/>
<object id="9" gid="5" x="32" y="32" width="16" height="16"/> <object id="9" gid="5" x="32" y="32" width="16" height="16"/>
@@ -29,5 +35,6 @@
<object id="12" gid="6" x="137" y="206" width="41" height="63"/> <object id="12" gid="6" x="137" y="206" width="41" height="63"/>
<object id="13" gid="6" x="72" y="93" width="41" height="63"/> <object id="13" gid="6" x="72" y="93" width="41" height="63"/>
<object id="14" gid="6" x="176" y="123" width="41" height="63"/> <object id="14" gid="6" x="176" y="123" width="41" height="63"/>
<object id="15" gid="7" x="96" y="128" width="16" height="16"/>
</objectgroup> </objectgroup>
</map> </map>

View File

@@ -30,6 +30,11 @@
"type": "string", "type": "string",
"value": "" "value": ""
}, },
{
"name": "animationSpeed",
"type": "float",
"value": 0
},
{ {
"name": "atlasAsset", "name": "atlasAsset",
"propertyType": "AtlasAsset", "propertyType": "AtlasAsset",

View File

@@ -1,9 +1,10 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<tileset version="1.10" tiledversion="1.11.0" name="objects" tilewidth="80" tileheight="112" tilecount="4" columns="0"> <tileset version="1.10" tiledversion="1.11.0" name="objects" tilewidth="80" tileheight="112" tilecount="5" columns="0">
<grid orientation="orthogonal" width="1" height="1"/> <grid orientation="orthogonal" width="1" height="1"/>
<tile id="1" type="Object"> <tile id="1" type="Object">
<properties> <properties>
<property name="animation" value="IDLE"/> <property name="animation" value="IDLE"/>
<property name="animationSpeed" type="float" value="1"/>
<property name="life" type="int" value="12"/> <property name="life" type="int" value="12"/>
<property name="lifeReg" type="float" value="0.25"/> <property name="lifeReg" type="float" value="0.25"/>
<property name="speed" type="float" value="3.5"/> <property name="speed" type="float" value="3.5"/>
@@ -35,4 +36,11 @@
</object> </object>
</objectgroup> </objectgroup>
</tile> </tile>
<tile id="6" type="Object">
<properties>
<property name="animation" value="IDLE"/>
<property name="z" type="int" value="0"/>
</properties>
<image source="objects/trap.png" width="16" height="16"/>
</tile>
</tileset> </tileset>

Binary file not shown.

After

Width:  |  Height:  |  Size: 281 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 11 KiB

After

Width:  |  Height:  |  Size: 12 KiB

View File

@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<tileset version="1.10" tiledversion="1.11.0" name="tileset" tilewidth="16" tileheight="16" spacing="16" margin="8" tilecount="128" columns="8"> <tileset version="1.10" tiledversion="1.11.0" name="tileset" tilewidth="16" tileheight="16" spacing="16" margin="8" tilecount="192" columns="12">
<image source="tileset.png" width="256" height="512"/> <image source="tileset.png" width="384" height="512"/>
<tile id="0"> <tile id="0">
<objectgroup draworder="index" id="2"> <objectgroup draworder="index" id="2">
<object id="1" x="8" y="9" width="8" height="7"/> <object id="1" x="8" y="9" width="8" height="7"/>
@@ -32,71 +32,79 @@
</objectgroup> </objectgroup>
</tile> </tile>
<tile id="8"> <tile id="8">
<animation>
<frame tileid="8" duration="200"/>
<frame tileid="9" duration="200"/>
<frame tileid="10" duration="200"/>
<frame tileid="11" duration="200"/>
</animation>
</tile>
<tile id="12">
<objectgroup draworder="index" id="2"> <objectgroup draworder="index" id="2">
<object id="1" x="8" y="0" width="4" height="16"/> <object id="1" x="8" y="0" width="4" height="16"/>
</objectgroup> </objectgroup>
</tile> </tile>
<tile id="10"> <tile id="14">
<objectgroup draworder="index" id="2"> <objectgroup draworder="index" id="2">
<object id="1" x="4" y="0" width="5" height="16"/> <object id="1" x="4" y="0" width="5" height="16"/>
</objectgroup> </objectgroup>
</tile> </tile>
<tile id="11"> <tile id="15">
<objectgroup draworder="index" id="2"> <objectgroup draworder="index" id="2">
<object id="1" x="7" y="0" width="5" height="16"/> <object id="1" x="7" y="0" width="5" height="16"/>
</objectgroup> </objectgroup>
</tile> </tile>
<tile id="13"> <tile id="17">
<objectgroup draworder="index" id="2"> <objectgroup draworder="index" id="2">
<object id="1" x="4" y="0" width="5" height="16"/> <object id="1" x="4" y="0" width="5" height="16"/>
</objectgroup> </objectgroup>
</tile> </tile>
<tile id="16"> <tile id="24">
<objectgroup draworder="index" id="2"> <objectgroup draworder="index" id="2">
<object id="1" x="9" y="0" width="7" height="8"/> <object id="1" x="9" y="0" width="7" height="8"/>
</objectgroup> </objectgroup>
</tile> </tile>
<tile id="17"> <tile id="25">
<objectgroup draworder="index" id="2"> <objectgroup draworder="index" id="2">
<object id="1" x="0" y="4" width="16" height="4"/> <object id="1" x="0" y="4" width="16" height="4"/>
</objectgroup> </objectgroup>
</tile> </tile>
<tile id="18"> <tile id="26">
<objectgroup draworder="index" id="2"> <objectgroup draworder="index" id="2">
<object id="1" x="0" y="0" width="7" height="7"/> <object id="1" x="0" y="0" width="7" height="7"/>
</objectgroup> </objectgroup>
</tile> </tile>
<tile id="19"> <tile id="27">
<objectgroup draworder="index" id="2"> <objectgroup draworder="index" id="2">
<object id="1" x="8" y="0" width="8" height="6"/> <object id="1" x="8" y="0" width="8" height="6"/>
</objectgroup> </objectgroup>
</tile> </tile>
<tile id="20"> <tile id="28">
<objectgroup draworder="index" id="2"> <objectgroup draworder="index" id="2">
<object id="1" x="0" y="6" width="16" height="4"/> <object id="1" x="0" y="6" width="16" height="4"/>
</objectgroup> </objectgroup>
</tile> </tile>
<tile id="21"> <tile id="29">
<objectgroup draworder="index" id="2"> <objectgroup draworder="index" id="2">
<object id="1" x="0" y="0" width="8" height="7"/> <object id="1" x="0" y="0" width="8" height="7"/>
</objectgroup> </objectgroup>
</tile> </tile>
<tile id="24"> <tile id="36">
<objectgroup draworder="index" id="2"> <objectgroup draworder="index" id="2">
<object id="1" x="4" y="5" width="12" height="11"/> <object id="1" x="4" y="5" width="12" height="11"/>
</objectgroup> </objectgroup>
</tile> </tile>
<tile id="25"> <tile id="37">
<objectgroup draworder="index" id="2"> <objectgroup draworder="index" id="2">
<object id="1" x="0" y="5" width="12" height="11"/> <object id="1" x="0" y="5" width="12" height="11"/>
</objectgroup> </objectgroup>
</tile> </tile>
<tile id="32"> <tile id="48">
<objectgroup draworder="index" id="2"> <objectgroup draworder="index" id="2">
<object id="1" x="4" y="0" width="12" height="14"/> <object id="1" x="4" y="0" width="12" height="14"/>
</objectgroup> </objectgroup>
</tile> </tile>
<tile id="33"> <tile id="49">
<objectgroup draworder="index" id="2"> <objectgroup draworder="index" id="2">
<object id="1" x="0" y="0" width="12" height="14"/> <object id="1" x="0" y="0" width="12" height="14"/>
</objectgroup> </objectgroup>
@@ -105,21 +113,21 @@
<wangset name="Unnamed Set" type="corner" tile="-1"> <wangset name="Unnamed Set" type="corner" tile="-1">
<wangcolor name="gras" color="#ff0000" tile="-1" probability="1"/> <wangcolor name="gras" color="#ff0000" tile="-1" probability="1"/>
<wangcolor name="dirt" color="#00ff00" tile="-1" probability="1"/> <wangcolor name="dirt" color="#00ff00" tile="-1" probability="1"/>
<wangtile tileid="9" wangid="0,1,0,1,0,1,0,1"/> <wangtile tileid="13" wangid="0,1,0,1,0,1,0,1"/>
<wangtile tileid="48" wangid="0,1,0,2,0,1,0,1"/> <wangtile tileid="72" wangid="0,1,0,2,0,1,0,1"/>
<wangtile tileid="49" wangid="0,1,0,2,0,2,0,1"/> <wangtile tileid="73" wangid="0,1,0,2,0,2,0,1"/>
<wangtile tileid="50" wangid="0,1,0,1,0,2,0,1"/> <wangtile tileid="74" wangid="0,1,0,1,0,2,0,1"/>
<wangtile tileid="56" wangid="0,2,0,2,0,1,0,1"/> <wangtile tileid="84" wangid="0,2,0,2,0,1,0,1"/>
<wangtile tileid="58" wangid="0,1,0,1,0,2,0,2"/> <wangtile tileid="86" wangid="0,1,0,1,0,2,0,2"/>
<wangtile tileid="64" wangid="0,2,0,1,0,1,0,1"/> <wangtile tileid="96" wangid="0,2,0,1,0,1,0,1"/>
<wangtile tileid="65" wangid="0,2,0,1,0,1,0,2"/> <wangtile tileid="97" wangid="0,2,0,1,0,1,0,2"/>
<wangtile tileid="66" wangid="0,1,0,1,0,1,0,2"/> <wangtile tileid="98" wangid="0,1,0,1,0,1,0,2"/>
<wangtile tileid="72" wangid="0,2,0,1,0,2,0,2"/> <wangtile tileid="108" wangid="0,2,0,1,0,2,0,2"/>
<wangtile tileid="73" wangid="0,2,0,2,0,1,0,2"/> <wangtile tileid="109" wangid="0,2,0,2,0,1,0,2"/>
<wangtile tileid="80" wangid="0,1,0,2,0,2,0,2"/> <wangtile tileid="120" wangid="0,1,0,2,0,2,0,2"/>
<wangtile tileid="81" wangid="0,2,0,2,0,2,0,1"/> <wangtile tileid="121" wangid="0,2,0,2,0,2,0,1"/>
<wangtile tileid="99" wangid="0,2,0,2,0,2,0,2"/> <wangtile tileid="147" wangid="0,2,0,2,0,2,0,2"/>
<wangtile tileid="121" wangid="0,1,0,1,0,1,0,1"/> <wangtile tileid="181" wangid="0,1,0,1,0,1,0,1"/>
</wangset> </wangset>
</wangsets> </wangsets>
</tileset> </tileset>

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.0 KiB

After

Width:  |  Height:  |  Size: 9.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 281 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 472 B

View File

@@ -3,6 +3,7 @@ package io.github.com.quillraven.asset;
public enum SoundAsset { public enum SoundAsset {
SWORD_HIT("sword_hit.wav"), SWORD_HIT("sword_hit.wav"),
LIFE_REG("life_reg.wav"), LIFE_REG("life_reg.wav"),
TRAP("trap.wav"),
; ;
private final String path; private final String path;

View File

@@ -68,10 +68,6 @@ public class Animation2D implements Component {
return playMode; return playMode;
} }
public float getSpeed() {
return speed;
}
public void setSpeed(float speed) { public void setSpeed(float speed) {
this.speed = speed; this.speed = speed;
} }

View File

@@ -0,0 +1,25 @@
package io.github.com.quillraven.component;
import com.badlogic.ashley.core.Component;
import com.badlogic.ashley.core.ComponentMapper;
import com.badlogic.gdx.maps.MapObject;
public class Tiled implements Component {
public static final ComponentMapper<Tiled> MAPPER = ComponentMapper.getFor(Tiled.class);
private final int id;
private final MapObject mapObjectRef;
public Tiled(MapObject mapObjectRef) {
this.id = mapObjectRef.getProperties().get("id", -1, Integer.class);
this.mapObjectRef = mapObjectRef;
}
public int getId() {
return id;
}
public MapObject getMapObjectRef() {
return mapObjectRef;
}
}

View File

@@ -0,0 +1,29 @@
package io.github.com.quillraven.component;
import com.badlogic.ashley.core.Component;
import com.badlogic.ashley.core.ComponentMapper;
import com.badlogic.ashley.core.Entity;
public class Trigger implements Component {
public static final ComponentMapper<Trigger> MAPPER = ComponentMapper.getFor(Trigger.class);
private final String name;
private Entity triggeringEntity;
public Trigger(String name) {
this.name = name;
this.triggeringEntity = null;
}
public String getName() {
return name;
}
public void setTriggeringEntity(Entity triggeringEntity) {
this.triggeringEntity = triggeringEntity;
}
public Entity getTriggeringEntity() {
return triggeringEntity;
}
}

View File

@@ -4,8 +4,4 @@ public class IdleControllerState implements ControllerState {
@Override @Override
public void keyDown(Command command) { public void keyDown(Command command) {
} }
@Override
public void keyUp(Command command) {
}
} }

View File

@@ -28,7 +28,8 @@ import io.github.com.quillraven.system.PhysicDebugRenderSystem;
import io.github.com.quillraven.system.PhysicMoveSystem; import io.github.com.quillraven.system.PhysicMoveSystem;
import io.github.com.quillraven.system.PhysicSystem; import io.github.com.quillraven.system.PhysicSystem;
import io.github.com.quillraven.system.RenderSystem; import io.github.com.quillraven.system.RenderSystem;
import io.github.com.quillraven.tiled.TiledAshleySpawner; import io.github.com.quillraven.system.TriggerSystem;
import io.github.com.quillraven.tiled.TiledAshleyConfigurator;
import io.github.com.quillraven.tiled.TiledService; import io.github.com.quillraven.tiled.TiledService;
import io.github.com.quillraven.ui.model.GameViewModel; import io.github.com.quillraven.ui.model.GameViewModel;
import io.github.com.quillraven.ui.view.GameView; import io.github.com.quillraven.ui.view.GameView;
@@ -43,7 +44,7 @@ public class GameScreen extends ScreenAdapter {
private final Viewport uiViewport; private final Viewport uiViewport;
private final TiledService tiledService; private final TiledService tiledService;
private final Engine engine; private final Engine engine;
private final TiledAshleySpawner tiledAshleySpawner; private final TiledAshleyConfigurator tiledAshleyConfigurator;
private final World physicWorld; private final World physicWorld;
private final KeyboardController keyboardController; private final KeyboardController keyboardController;
private final AudioService audioService; private final AudioService audioService;
@@ -55,11 +56,11 @@ public class GameScreen extends ScreenAdapter {
this.skin = game.getAssetService().get(SkinAsset.DEFAULT); this.skin = game.getAssetService().get(SkinAsset.DEFAULT);
this.viewModel = new GameViewModel(game); this.viewModel = new GameViewModel(game);
this.audioService = game.getAudioService(); this.audioService = game.getAudioService();
this.tiledService = new TiledService(game.getAssetService());
this.physicWorld = new World(Vector2.Zero, true); this.physicWorld = new World(Vector2.Zero, true);
this.physicWorld.setAutoClearForces(false); this.physicWorld.setAutoClearForces(false);
this.tiledService = new TiledService(game.getAssetService(), this.physicWorld);
this.engine = new Engine(); this.engine = new Engine();
this.tiledAshleySpawner = new TiledAshleySpawner(this.engine, this.physicWorld, this.game.getAssetService()); this.tiledAshleyConfigurator = new TiledAshleyConfigurator(this.engine, this.physicWorld, this.game.getAssetService());
this.keyboardController = new KeyboardController(GameControllerState.class, engine, null); this.keyboardController = new KeyboardController(GameControllerState.class, engine, null);
// add ECS systems // add ECS systems
@@ -67,6 +68,7 @@ public class GameScreen extends ScreenAdapter {
this.engine.addSystem(new PhysicSystem(physicWorld, 1 / 60f)); this.engine.addSystem(new PhysicSystem(physicWorld, 1 / 60f));
this.engine.addSystem(new FacingSystem()); this.engine.addSystem(new FacingSystem());
this.engine.addSystem(new FsmSystem()); this.engine.addSystem(new FsmSystem());
this.engine.addSystem(new TriggerSystem(audioService));
this.engine.addSystem(new LifeSystem(this.viewModel)); this.engine.addSystem(new LifeSystem(this.viewModel));
this.engine.addSystem(new AnimationSystem(game.getAssetService())); this.engine.addSystem(new AnimationSystem(game.getAssetService()));
this.engine.addSystem(new CameraSystem(game.getCamera())); this.engine.addSystem(new CameraSystem(game.getCamera()));
@@ -83,12 +85,12 @@ public class GameScreen extends ScreenAdapter {
this.stage.addActor(new GameView(stage, skin, this.viewModel)); this.stage.addActor(new GameView(stage, skin, this.viewModel));
Consumer<TiledMap> renderConsumer = this.engine.getSystem(RenderSystem.class)::setMap; Consumer<TiledMap> renderConsumer = this.engine.getSystem(RenderSystem.class)::setMap;
Consumer<TiledMap> ashleySpawnerConsumer = this.tiledAshleySpawner::loadMapObjects;
Consumer<TiledMap> cameraConsumer = this.engine.getSystem(CameraSystem.class)::setMap; Consumer<TiledMap> cameraConsumer = this.engine.getSystem(CameraSystem.class)::setMap;
Consumer<TiledMap> audioConsumer = this.audioService::setMap; Consumer<TiledMap> audioConsumer = this.audioService::setMap;
this.tiledService.setMapChangeConsumer( this.tiledService.setMapChangeConsumer(renderConsumer.andThen(cameraConsumer).andThen(audioConsumer));
renderConsumer.andThen(ashleySpawnerConsumer).andThen(cameraConsumer).andThen(audioConsumer) this.tiledService.setLoadTriggerConsumer(tiledAshleyConfigurator::onLoadTrigger);
); this.tiledService.setLoadObjectConsumer(tiledAshleyConfigurator::onLoadObject);
this.tiledService.setLoadTileConsumer(tiledAshleyConfigurator::onLoadTile);
TiledMap startMap = this.tiledService.loadMap(MapAsset.MAIN); TiledMap startMap = this.tiledService.loadMap(MapAsset.MAIN);
this.tiledService.setMap(startMap); this.tiledService.setMap(startMap);

View File

@@ -7,11 +7,17 @@ import com.badlogic.ashley.core.Family;
import com.badlogic.ashley.systems.IteratingSystem; import com.badlogic.ashley.systems.IteratingSystem;
import com.badlogic.gdx.math.MathUtils; import com.badlogic.gdx.math.MathUtils;
import com.badlogic.gdx.physics.box2d.Body; import com.badlogic.gdx.physics.box2d.Body;
import com.badlogic.gdx.physics.box2d.Contact;
import com.badlogic.gdx.physics.box2d.ContactImpulse;
import com.badlogic.gdx.physics.box2d.ContactListener;
import com.badlogic.gdx.physics.box2d.Manifold;
import com.badlogic.gdx.physics.box2d.World; import com.badlogic.gdx.physics.box2d.World;
import io.github.com.quillraven.component.Physic; import io.github.com.quillraven.component.Physic;
import io.github.com.quillraven.component.Player;
import io.github.com.quillraven.component.Transform; import io.github.com.quillraven.component.Transform;
import io.github.com.quillraven.component.Trigger;
public class PhysicSystem extends IteratingSystem implements EntityListener { public class PhysicSystem extends IteratingSystem implements EntityListener, ContactListener {
private final World world; private final World world;
private final float interval; private final float interval;
@@ -22,6 +28,7 @@ public class PhysicSystem extends IteratingSystem implements EntityListener {
this.world = world; this.world = world;
this.interval = interval; this.interval = interval;
this.accumulator = 0f; this.accumulator = 0f;
world.setContactListener(this);
} }
@Override @Override
@@ -86,4 +93,42 @@ public class PhysicSystem extends IteratingSystem implements EntityListener {
} }
} }
@Override
public void beginContact(Contact contact) {
Object userDataA = contact.getFixtureA().getBody().getUserData();
Object userDataB = contact.getFixtureB().getBody().getUserData();
if (!(userDataA instanceof Entity entityA) || !(userDataB instanceof Entity entityB)) {
return;
}
playerTriggerContact(entityA, entityB);
}
private static void playerTriggerContact(Entity entityA, Entity entityB) {
Trigger trigger = Trigger.MAPPER.get(entityA);
boolean isPlayer = Player.MAPPER.get(entityB) != null;
if (trigger != null && isPlayer) {
trigger.setTriggeringEntity(entityB);
return;
}
trigger = Trigger.MAPPER.get(entityB);
isPlayer = Player.MAPPER.get(entityA) != null;
if (trigger != null && isPlayer) {
trigger.setTriggeringEntity(entityA);
}
}
@Override
public void endContact(Contact contact) {
}
@Override
public void preSolve(Contact contact, Manifold oldManifold) {
}
@Override
public void postSolve(Contact contact, ContactImpulse impulse) {
}
} }

View File

@@ -0,0 +1,75 @@
package io.github.com.quillraven.system;
import com.badlogic.ashley.core.Entity;
import com.badlogic.ashley.core.Family;
import com.badlogic.ashley.systems.IteratingSystem;
import com.badlogic.ashley.utils.ImmutableArray;
import com.badlogic.gdx.graphics.g2d.Animation;
import com.badlogic.gdx.utils.GdxRuntimeException;
import com.badlogic.gdx.utils.Timer;
import io.github.com.quillraven.asset.SoundAsset;
import io.github.com.quillraven.audio.AudioService;
import io.github.com.quillraven.component.Animation2D;
import io.github.com.quillraven.component.Life;
import io.github.com.quillraven.component.Tiled;
import io.github.com.quillraven.component.Trigger;
public class TriggerSystem extends IteratingSystem {
private final AudioService audioService;
public TriggerSystem(AudioService audioService) {
super(Family.all(Trigger.class).get());
this.audioService = audioService;
}
@Override
protected void processEntity(Entity entity, float deltaTime) {
Trigger trigger = Trigger.MAPPER.get(entity);
if (trigger.getTriggeringEntity() == null) return;
fireTrigger(trigger.getName(), trigger.getTriggeringEntity());
trigger.setTriggeringEntity(null);
}
private Entity getByTiledId(int tiledId) {
ImmutableArray<Entity> entities = getEngine().getEntitiesFor(Family.all(Tiled.class).get());
for (Entity entity : entities) {
if (Tiled.MAPPER.get(entity).getId() == tiledId) {
return entity;
}
}
return null;
}
private void fireTrigger(String triggerName, Entity triggeringEntity) {
switch (triggerName) {
case "trap_trigger" -> trapTrigger(triggeringEntity);
default -> throw new GdxRuntimeException("Unsupported trigger: " + triggerName);
}
}
private void trapTrigger(Entity triggeringEntity) {
Entity trapEntity = getByTiledId(15);
if (trapEntity != null) {
// play trap animation
Animation2D animation2D = Animation2D.MAPPER.get(trapEntity);
animation2D.setSpeed(1f);
animation2D.setPlayMode(Animation.PlayMode.NORMAL);
audioService.playSound(SoundAsset.TRAP);
// reset animation
Timer.schedule(new Timer.Task() {
@Override
public void run() {
animation2D.setSpeed(0f);
animation2D.setType(Animation2D.AnimationType.IDLE);
}
}, 2.5f);
// damage player
Life life = Life.MAPPER.get(triggeringEntity);
if (life.getLife() > 2) {
life.addLife(-2f);
}
}
}
}

View File

@@ -7,13 +7,10 @@ import com.badlogic.gdx.graphics.g2d.Animation;
import com.badlogic.gdx.graphics.g2d.TextureAtlas; import com.badlogic.gdx.graphics.g2d.TextureAtlas;
import com.badlogic.gdx.graphics.g2d.TextureRegion; import com.badlogic.gdx.graphics.g2d.TextureRegion;
import com.badlogic.gdx.graphics.glutils.FileTextureData; import com.badlogic.gdx.graphics.glutils.FileTextureData;
import com.badlogic.gdx.maps.MapLayer;
import com.badlogic.gdx.maps.MapObject; import com.badlogic.gdx.maps.MapObject;
import com.badlogic.gdx.maps.MapObjects; import com.badlogic.gdx.maps.MapObjects;
import com.badlogic.gdx.maps.objects.RectangleMapObject; import com.badlogic.gdx.maps.objects.RectangleMapObject;
import com.badlogic.gdx.maps.tiled.TiledMap;
import com.badlogic.gdx.maps.tiled.TiledMapTile; import com.badlogic.gdx.maps.tiled.TiledMapTile;
import com.badlogic.gdx.maps.tiled.TiledMapTileLayer;
import com.badlogic.gdx.maps.tiled.objects.TiledMapTileMapObject; import com.badlogic.gdx.maps.tiled.objects.TiledMapTileMapObject;
import com.badlogic.gdx.math.Rectangle; import com.badlogic.gdx.math.Rectangle;
import com.badlogic.gdx.math.Vector2; import com.badlogic.gdx.math.Vector2;
@@ -21,7 +18,6 @@ import com.badlogic.gdx.physics.box2d.Body;
import com.badlogic.gdx.physics.box2d.BodyDef; import com.badlogic.gdx.physics.box2d.BodyDef;
import com.badlogic.gdx.physics.box2d.BodyDef.BodyType; import com.badlogic.gdx.physics.box2d.BodyDef.BodyType;
import com.badlogic.gdx.physics.box2d.FixtureDef; import com.badlogic.gdx.physics.box2d.FixtureDef;
import com.badlogic.gdx.physics.box2d.PolygonShape;
import com.badlogic.gdx.physics.box2d.World; import com.badlogic.gdx.physics.box2d.World;
import com.badlogic.gdx.utils.GdxRuntimeException; import com.badlogic.gdx.utils.GdxRuntimeException;
import io.github.com.quillraven.GdxGame; import io.github.com.quillraven.GdxGame;
@@ -39,10 +35,12 @@ import io.github.com.quillraven.component.Life;
import io.github.com.quillraven.component.Move; import io.github.com.quillraven.component.Move;
import io.github.com.quillraven.component.Physic; import io.github.com.quillraven.component.Physic;
import io.github.com.quillraven.component.Player; import io.github.com.quillraven.component.Player;
import io.github.com.quillraven.component.Tiled;
import io.github.com.quillraven.component.Transform; import io.github.com.quillraven.component.Transform;
import io.github.com.quillraven.component.Trigger;
public class TiledAshleySpawner { public class TiledAshleyConfigurator {
private static final Vector2 DEFAULT_SCALING = new Vector2(1f, 1f); private static final Vector2 DEFAULT_PHYSIC_SCALING = new Vector2(1f, 1f);
private final Engine engine; private final Engine engine;
private final World physicWorld; private final World physicWorld;
@@ -50,7 +48,7 @@ public class TiledAshleySpawner {
private final Vector2 tmpVec2; private final Vector2 tmpVec2;
private final AssetService assetService; private final AssetService assetService;
public TiledAshleySpawner(Engine engine, World physicWorld, AssetService assetService) { public TiledAshleyConfigurator(Engine engine, World physicWorld, AssetService assetService) {
this.engine = engine; this.engine = engine;
this.physicWorld = physicWorld; this.physicWorld = physicWorld;
this.tmpMapObjects = new MapObjects(); this.tmpMapObjects = new MapObjects();
@@ -58,120 +56,49 @@ public class TiledAshleySpawner {
this.assetService = assetService; this.assetService = assetService;
} }
public void loadMapObjects(TiledMap tiledMap) { public void onLoadTile(TiledMapTile tile, float x, float y) {
for (MapLayer layer : tiledMap.getLayers()) { createBody(tile.getObjects(),
if (layer instanceof TiledMapTileLayer tileLayer) { new Vector2(x, y),
loadTileLayer(tileLayer); DEFAULT_PHYSIC_SCALING,
} else if ("objects".equals(layer.getName())) { BodyDef.BodyType.StaticBody,
loadObjectLayer(layer); Vector2.Zero,
} else if ("trigger".equals(layer.getName())) { "environment");
loadTriggerLayer(layer);
}
}
spawnMapBoundary(tiledMap);
} }
private void spawnMapBoundary(TiledMap tiledMap) { public void onLoadTrigger(String triggerName, MapObject mapObject) {
// create four boxes for the map boundary (left, right, bottom and top edge) if (mapObject instanceof RectangleMapObject rectMapObj) {
int width = tiledMap.getProperties().get("width", 0, Integer.class); Entity entity = this.engine.createEntity();
int tileW = tiledMap.getProperties().get("tilewidth", 0, Integer.class); Rectangle rect = rectMapObj.getRectangle();
int height = tiledMap.getProperties().get("height", 0, Integer.class); addEntityTransform(
int tileH = tiledMap.getProperties().get("tileheight", 0, Integer.class); rect.getX(), rect.getY(), 0,
float mapW = width * tileW * GdxGame.UNIT_SCALE; rect.getWidth(), rect.getHeight(),
float mapH = height * tileH * GdxGame.UNIT_SCALE; 1f, 1f,
float halfW = mapW * 0.5f; 0,
float halfH = mapH * 0.5f; entity);
float boxThickness = 0.5f; addEntityPhysic(
rectMapObj,
BodyDef bodyDef = new BodyDef(); BodyDef.BodyType.StaticBody,
bodyDef.type = BodyType.StaticBody; tmpVec2.set(rect.getX(), rect.getY()).scl(GdxGame.UNIT_SCALE),
bodyDef.position.setZero(); entity);
bodyDef.fixedRotation = true; entity.add(new Trigger(triggerName));
Body body = physicWorld.createBody(bodyDef); entity.add(new Tiled(rectMapObj));
this.engine.addEntity(entity);
// left edge } else {
PolygonShape shape = new PolygonShape(); throw new GdxRuntimeException("Unsupported map object type for trigger: " + mapObject.getClass().getSimpleName());
shape.setAsBox(boxThickness, halfH, new Vector2(-boxThickness, halfH), 0f);
body.createFixture(shape, 0f).setFriction(0f);
shape.dispose();
// right edge
shape = new PolygonShape();
shape.setAsBox(boxThickness, halfH, new Vector2(mapW + boxThickness, halfH), 0f);
body.createFixture(shape, 0f).setFriction(0f);
shape.dispose();
// bottom edge
shape = new PolygonShape();
shape.setAsBox(halfW, boxThickness, new Vector2(halfW, -boxThickness), 0f);
body.createFixture(shape, 0f).setFriction(0f);
shape.dispose();
// top edge
shape = new PolygonShape();
shape.setAsBox(halfW, boxThickness, new Vector2(halfW, mapH + boxThickness), 0f);
body.createFixture(shape, 0f).setFriction(0f);
shape.dispose();
}
private void loadTileLayer(TiledMapTileLayer tileLayer) {
for (int y = 0; y < tileLayer.getHeight(); y++) {
for (int x = 0; x < tileLayer.getWidth(); x++) {
TiledMapTileLayer.Cell cell = tileLayer.getCell(x, y);
if (cell == null) continue;
TiledMapTile tile = cell.getTile();
createBody(tile.getObjects(),
new Vector2(x, y),
DEFAULT_SCALING,
BodyType.StaticBody,
Vector2.Zero,
"environment");
}
} }
} }
private void loadTriggerLayer(MapLayer triggerLayer) { public void onLoadObject(TiledMapTileMapObject tileMapObject) {
for (MapObject mapObject : triggerLayer.getObjects()) {
if (mapObject instanceof RectangleMapObject rectMapObj) {
Entity entity = this.engine.createEntity();
Rectangle rect = rectMapObj.getRectangle();
addEntityTransform(
rect.getX(), rect.getY(),
rect.getWidth(), rect.getHeight(),
1f, 1f,
0,
entity);
addEntityPhysic(
rectMapObj,
BodyType.StaticBody,
tmpVec2.set(rect.getX(), rect.getY()).scl(GdxGame.UNIT_SCALE),
entity);
this.engine.addEntity(entity);
} else {
throw new GdxRuntimeException("Unsupported trigger: " + mapObject.getClass().getSimpleName());
}
}
}
private void loadObjectLayer(MapLayer objectLayer) {
for (MapObject mapObject : objectLayer.getObjects()) {
if (mapObject instanceof TiledMapTileMapObject tileMapObject) {
spawnEntityOf(tileMapObject);
} else {
throw new GdxRuntimeException("Unsupported object: " + mapObject.getClass().getSimpleName());
}
}
}
private void spawnEntityOf(TiledMapTileMapObject tileMapObject) {
Entity entity = this.engine.createEntity(); Entity entity = this.engine.createEntity();
TiledMapTile tile = tileMapObject.getTile(); TiledMapTile tile = tileMapObject.getTile();
TextureRegion textureRegion = getTextureRegion(tile); TextureRegion textureRegion = getTextureRegion(tile);
String classType = tile.getProperties().get("type", "", String.class); String classType = tile.getProperties().get("type", "", String.class);
float sortOffsetY = tile.getProperties().get("sortOffsetY", 0, Integer.class); float sortOffsetY = tile.getProperties().get("sortOffsetY", 0, Integer.class);
sortOffsetY *= GdxGame.UNIT_SCALE; sortOffsetY *= GdxGame.UNIT_SCALE;
int z = tile.getProperties().get("z", 1, Integer.class);
addEntityTransform( addEntityTransform(
tileMapObject.getX(), tileMapObject.getY(), tileMapObject.getX(), tileMapObject.getY(), z,
textureRegion.getRegionWidth(), textureRegion.getRegionHeight(), textureRegion.getRegionWidth(), textureRegion.getRegionHeight(),
tileMapObject.getScaleX(), tileMapObject.getScaleY(), tileMapObject.getScaleX(), tileMapObject.getScaleY(),
sortOffsetY, sortOffsetY,
@@ -190,6 +117,7 @@ public class TiledAshleySpawner {
entity.add(new Facing(FacingDirection.DOWN)); entity.add(new Facing(FacingDirection.DOWN));
entity.add(new Fsm(entity)); entity.add(new Fsm(entity));
entity.add(new Graphic(textureRegion, Color.WHITE.cpy())); entity.add(new Graphic(textureRegion, Color.WHITE.cpy()));
entity.add(new Tiled(tileMapObject));
this.engine.addEntity(entity); this.engine.addEntity(entity);
} }
@@ -258,8 +186,9 @@ public class TiledAshleySpawner {
AtlasAsset atlasAsset = AtlasAsset.valueOf(atlasAssetStr); AtlasAsset atlasAsset = AtlasAsset.valueOf(atlasAssetStr);
FileTextureData textureData = (FileTextureData) tile.getTextureRegion().getTexture().getTextureData(); FileTextureData textureData = (FileTextureData) tile.getTextureRegion().getTexture().getTextureData();
String atlasKey = textureData.getFileHandle().nameWithoutExtension(); String atlasKey = textureData.getFileHandle().nameWithoutExtension();
float speed = tile.getProperties().get("animationSpeed", 0f, Float.class);
entity.add(new Animation2D(atlasAsset, atlasKey, animationType, Animation.PlayMode.LOOP, 1f)); entity.add(new Animation2D(atlasAsset, atlasKey, animationType, Animation.PlayMode.LOOP, speed));
} }
private void addEntityPhysic(MapObject mapObject, @SuppressWarnings("SameParameterValue") BodyType bodyType, Vector2 relativeTo, Entity entity) { private void addEntityPhysic(MapObject mapObject, @SuppressWarnings("SameParameterValue") BodyType bodyType, Vector2 relativeTo, Entity entity) {
@@ -305,7 +234,7 @@ public class TiledAshleySpawner {
} }
private static void addEntityTransform( private static void addEntityTransform(
float x, float y, float x, float y, int z,
float w, float h, float w, float h,
float scaleX, float scaleY, float scaleX, float scaleY,
float sortOffsetY, float sortOffsetY,
@@ -318,7 +247,7 @@ public class TiledAshleySpawner {
position.scl(GdxGame.UNIT_SCALE); position.scl(GdxGame.UNIT_SCALE);
size.scl(GdxGame.UNIT_SCALE); size.scl(GdxGame.UNIT_SCALE);
entity.add(new Transform(position, 0, size, scaling, 0f, sortOffsetY)); entity.add(new Transform(position, z, size, scaling, 0f, sortOffsetY));
} }
} }

View File

@@ -1,19 +1,43 @@
package io.github.com.quillraven.tiled; package io.github.com.quillraven.tiled;
import com.badlogic.gdx.maps.MapLayer;
import com.badlogic.gdx.maps.MapObject;
import com.badlogic.gdx.maps.objects.RectangleMapObject;
import com.badlogic.gdx.maps.tiled.TiledMap; import com.badlogic.gdx.maps.tiled.TiledMap;
import com.badlogic.gdx.maps.tiled.TiledMapTile;
import com.badlogic.gdx.maps.tiled.TiledMapTileLayer;
import com.badlogic.gdx.maps.tiled.objects.TiledMapTileMapObject;
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.PolygonShape;
import com.badlogic.gdx.physics.box2d.World;
import com.badlogic.gdx.utils.GdxRuntimeException;
import io.github.com.quillraven.GdxGame;
import io.github.com.quillraven.asset.AssetService; import io.github.com.quillraven.asset.AssetService;
import io.github.com.quillraven.asset.MapAsset; import io.github.com.quillraven.asset.MapAsset;
import java.util.function.BiConsumer;
import java.util.function.Consumer; import java.util.function.Consumer;
public class TiledService { public class TiledService {
private final AssetService assetService; private final AssetService assetService;
private Consumer<TiledMap> mapChangeConsumer; private final World physicWorld;
private TiledMap currentMap; private TiledMap currentMap;
public TiledService(AssetService assetService) { private Consumer<TiledMap> mapChangeConsumer;
private BiConsumer<String, MapObject> loadTriggerConsumer;
private Consumer<TiledMapTileMapObject> loadObjectConsumer;
private LoadTileConsumer loadTileConsumer;
public TiledService(AssetService assetService, World physicWorld) {
this.assetService = assetService; this.assetService = assetService;
this.physicWorld = physicWorld;
this.mapChangeConsumer = null; this.mapChangeConsumer = null;
this.loadTriggerConsumer = null;
this.loadObjectConsumer = null;
this.loadTileConsumer = null;
this.currentMap = null; this.currentMap = null;
} }
@@ -29,6 +53,7 @@ public class TiledService {
} }
this.currentMap = tiledMap; this.currentMap = tiledMap;
loadMapObjects(tiledMap);
if (this.mapChangeConsumer != null) { if (this.mapChangeConsumer != null) {
this.mapChangeConsumer.accept(tiledMap); this.mapChangeConsumer.accept(tiledMap);
} }
@@ -37,4 +62,116 @@ public class TiledService {
public void setMapChangeConsumer(Consumer<TiledMap> mapChangeConsumer) { public void setMapChangeConsumer(Consumer<TiledMap> mapChangeConsumer) {
this.mapChangeConsumer = mapChangeConsumer; this.mapChangeConsumer = mapChangeConsumer;
} }
public void setLoadObjectConsumer(Consumer<TiledMapTileMapObject> loadObjectConsumer) {
this.loadObjectConsumer = loadObjectConsumer;
}
public void setLoadTriggerConsumer(BiConsumer<String, MapObject> loadTriggerConsumer) {
this.loadTriggerConsumer = loadTriggerConsumer;
}
public void setLoadTileConsumer(LoadTileConsumer loadTileConsumer) {
this.loadTileConsumer = loadTileConsumer;
}
public void loadMapObjects(TiledMap tiledMap) {
for (MapLayer layer : tiledMap.getLayers()) {
if (layer instanceof TiledMapTileLayer tileLayer) {
loadTileLayer(tileLayer);
} else if ("objects".equals(layer.getName())) {
loadObjectLayer(layer);
} else if ("trigger".equals(layer.getName())) {
loadTriggerLayer(layer);
}
}
spawnMapBoundary(tiledMap);
}
private void spawnMapBoundary(TiledMap tiledMap) {
// create four boxes for the map boundary (left, right, bottom and top edge)
int width = tiledMap.getProperties().get("width", 0, Integer.class);
int tileW = tiledMap.getProperties().get("tilewidth", 0, Integer.class);
int height = tiledMap.getProperties().get("height", 0, Integer.class);
int tileH = tiledMap.getProperties().get("tileheight", 0, Integer.class);
float mapW = width * tileW * GdxGame.UNIT_SCALE;
float mapH = height * tileH * GdxGame.UNIT_SCALE;
float halfW = mapW * 0.5f;
float halfH = mapH * 0.5f;
float boxThickness = 0.5f;
BodyDef bodyDef = new BodyDef();
bodyDef.type = BodyDef.BodyType.StaticBody;
bodyDef.position.setZero();
bodyDef.fixedRotation = true;
Body body = physicWorld.createBody(bodyDef);
// left edge
PolygonShape shape = new PolygonShape();
shape.setAsBox(boxThickness, halfH, new Vector2(-boxThickness, halfH), 0f);
body.createFixture(shape, 0f).setFriction(0f);
shape.dispose();
// right edge
shape = new PolygonShape();
shape.setAsBox(boxThickness, halfH, new Vector2(mapW + boxThickness, halfH), 0f);
body.createFixture(shape, 0f).setFriction(0f);
shape.dispose();
// bottom edge
shape = new PolygonShape();
shape.setAsBox(halfW, boxThickness, new Vector2(halfW, -boxThickness), 0f);
body.createFixture(shape, 0f).setFriction(0f);
shape.dispose();
// top edge
shape = new PolygonShape();
shape.setAsBox(halfW, boxThickness, new Vector2(halfW, mapH + boxThickness), 0f);
body.createFixture(shape, 0f).setFriction(0f);
shape.dispose();
}
private void loadTileLayer(TiledMapTileLayer tileLayer) {
if (loadTileConsumer == null) return;
for (int y = 0; y < tileLayer.getHeight(); y++) {
for (int x = 0; x < tileLayer.getWidth(); x++) {
TiledMapTileLayer.Cell cell = tileLayer.getCell(x, y);
if (cell == null) continue;
loadTileConsumer.accept(cell.getTile(), x, y);
}
}
}
private void loadTriggerLayer(MapLayer triggerLayer) {
if (loadTriggerConsumer == null) return;
for (MapObject mapObject : triggerLayer.getObjects()) {
if (mapObject.getName() == null || mapObject.getName().isBlank()) {
throw new GdxRuntimeException("Trigger must have a name: " + mapObject);
}
if (mapObject instanceof RectangleMapObject rectMapObj) {
loadTriggerConsumer.accept(mapObject.getName(), rectMapObj);
} else {
throw new GdxRuntimeException("Unsupported trigger: " + mapObject.getClass().getSimpleName());
}
}
}
private void loadObjectLayer(MapLayer objectLayer) {
if (loadObjectConsumer == null) return;
for (MapObject mapObject : objectLayer.getObjects()) {
if (mapObject instanceof TiledMapTileMapObject tileMapObject) {
loadObjectConsumer.accept(tileMapObject);
} else {
throw new GdxRuntimeException("Unsupported object: " + mapObject.getClass().getSimpleName());
}
}
}
@FunctionalInterface
public interface LoadTileConsumer {
void accept(TiledMapTile tile, float x, float y);
}
} }

View File

@@ -33,7 +33,7 @@ public class GameViewModel extends ViewModel {
public void setLifePoints(int lifePoints) { public void setLifePoints(int lifePoints) {
if (this.lifePoints != lifePoints) { if (this.lifePoints != lifePoints) {
this.propertyChangeSupport.firePropertyChange(LIFE_POINTS, this.lifePoints, lifePoints); this.propertyChangeSupport.firePropertyChange(LIFE_POINTS, this.lifePoints, lifePoints);
if (this.lifePoints < lifePoints) { if (this.lifePoints != 0 && this.lifePoints < lifePoints) {
audioService.playSound(SoundAsset.LIFE_REG); audioService.playSound(SoundAsset.LIFE_REG);
} }
} }