Fixed enemy spawning in structures

reduced segmented WaveFunctionCollapse calculation for better performance
added flying to enemies
This commit is contained in:
Grimm
2022-08-08 15:08:02 +02:00
parent d1cb4c3825
commit 2e9dc4791d
15 changed files with 325 additions and 205 deletions

View File

@@ -11,10 +11,13 @@ public class EnemyEdit extends FormPanel {
EnemyData currentData; EnemyData currentData;
JTextField nameField=new JTextField(); JTextField nameField=new JTextField();
JTextField colorField=new JTextField(); JTextField colorField=new JTextField();
JSpinner lifeFiled= new JSpinner(new SpinnerNumberModel(0, 0, 1000, 1)); JTextField ai=new JTextField();
JSpinner spawnRate= new JSpinner(new SpinnerNumberModel(0.0, 0., 1, 0.1)); JCheckBox flying=new JCheckBox();
JSpinner difficulty= new JSpinner(new SpinnerNumberModel(0.0, 0., 1, 0.1)); JCheckBox boss=new JCheckBox();
JSpinner speed= new JSpinner(new SpinnerNumberModel(0.0, 0., 100., 1.0)); FloatSpinner lifeFiled= new FloatSpinner(0, 1000, 1);
FloatSpinner spawnRate= new FloatSpinner( 0.f, 1, 0.1f);
FloatSpinner difficulty= new FloatSpinner( 0.f, 1, 0.1f);
FloatSpinner speed= new FloatSpinner( 0.f, 100.f, 1.0f);
FilePicker deck=new FilePicker(new String[]{"dck","json"}); FilePicker deck=new FilePicker(new String[]{"dck","json"});
FilePicker atlas=new FilePicker(new String[]{"atlas"}); FilePicker atlas=new FilePicker(new String[]{"atlas"});
JTextField equipment=new JTextField(); JTextField equipment=new JTextField();
@@ -36,13 +39,23 @@ public class EnemyEdit extends FormPanel {
center.add("Sprite:",atlas); center.add("Sprite:",atlas);
center.add("Equipment:",equipment); center.add("Equipment:",equipment);
center.add("Colors:",colorField); center.add("Colors:",colorField);
center.add("ai:",ai);
center.add("flying:",flying);
center.add("boss:",boss);
add(preview);
add(center); add(center);
add(rewards); add(rewards);
add(preview);
equipment.getDocument().addDocumentListener(new DocumentChangeListener(() -> EnemyEdit.this.updateEnemy())); equipment.getDocument().addDocumentListener(new DocumentChangeListener(() -> EnemyEdit.this.updateEnemy()));
atlas.getEdit().getDocument().addDocumentListener(new DocumentChangeListener(() -> EnemyEdit.this.updateEnemy())); atlas.getEdit().getDocument().addDocumentListener(new DocumentChangeListener(() -> EnemyEdit.this.updateEnemy()));
colorField.getDocument().addDocumentListener(new DocumentChangeListener(() -> EnemyEdit.this.updateEnemy())); colorField.getDocument().addDocumentListener(new DocumentChangeListener(() -> EnemyEdit.this.updateEnemy()));
ai.getDocument().addDocumentListener(new DocumentChangeListener(() -> EnemyEdit.this.updateEnemy()));
flying.addChangeListener(e -> EnemyEdit.this.updateEnemy());
boss.addChangeListener(e -> EnemyEdit.this.updateEnemy());
nameField.getDocument().addDocumentListener(new DocumentChangeListener(() -> EnemyEdit.this.updateEnemy())); nameField.getDocument().addDocumentListener(new DocumentChangeListener(() -> EnemyEdit.this.updateEnemy()));
deck.getEdit().getDocument().addDocumentListener(new DocumentChangeListener(() -> EnemyEdit.this.updateEnemy())); deck.getEdit().getDocument().addDocumentListener(new DocumentChangeListener(() -> EnemyEdit.this.updateEnemy()));
lifeFiled.addChangeListener(e -> EnemyEdit.this.updateEnemy()); lifeFiled.addChangeListener(e -> EnemyEdit.this.updateEnemy());
@@ -59,6 +72,9 @@ public class EnemyEdit extends FormPanel {
return; return;
currentData.name=nameField.getText(); currentData.name=nameField.getText();
currentData.colors=colorField.getText(); currentData.colors=colorField.getText();
currentData.ai=ai.getText();
currentData.flying=flying.isSelected();
currentData.boss=boss.isSelected();
currentData.life= (int) lifeFiled.getValue(); currentData.life= (int) lifeFiled.getValue();
currentData.sprite= atlas.getEdit().getText(); currentData.sprite= atlas.getEdit().getText();
if(equipment.getText().isEmpty()) if(equipment.getText().isEmpty())
@@ -88,6 +104,9 @@ public class EnemyEdit extends FormPanel {
updating=true; updating=true;
nameField.setText(currentData.name); nameField.setText(currentData.name);
colorField.setText(currentData.colors); colorField.setText(currentData.colors);
ai.setText(currentData.ai);
boss.setSelected(currentData.boss);
flying.setSelected(currentData.flying);
lifeFiled.setValue(currentData.life); lifeFiled.setValue(currentData.life);
atlas.getEdit().setText(currentData.sprite); atlas.getEdit().setText(currentData.sprite);
if(currentData.equipment!=null) if(currentData.equipment!=null)

View File

@@ -40,7 +40,7 @@ public class SwingAtlasPreview extends Box {
setSpritePath(sprite,null); setSpritePath(sprite,null);
} }
public void setSpritePath(String sprite,String name) { public void setSpritePath(String sprite,String name) {
if(this.sprite==null||name==null||sprite==null||(this.sprite.equals(sprite)&&(spriteName==null&&spriteName.equals(name)))) if(this.sprite==null||sprite==null||(this.sprite.equals(sprite)&&(spriteName!=null&&name!=null&&spriteName.equals(name))))
return; return;
removeAll(); removeAll();
counter=0; counter=0;

View File

@@ -56,8 +56,14 @@ public class CharacterSprite extends MapActor {
anim = atlas.createSprites(stand.toString()); anim = atlas.createSprites(stand.toString());
else else
anim = atlas.createSprites(stand.toString() + dir.toString()); anim = atlas.createSprites(stand.toString() + dir.toString());
if (anim.size != 0) { if (anim.size != 0) {
dirs.put(dir, new Animation<>(0.2f, anim)); dirs.put(dir, new Animation<>(0.2f, anim));
if(getWidth()==0.0)//init size onload
{
setWidth(anim.first().getWidth());
setHeight(anim.first().getHeight());
}
} }
} }
animations.put(stand, dirs); animations.put(stand, dirs);

View File

@@ -55,9 +55,8 @@ public class MapActor extends Actor {
} }
@Override @Override
protected void positionChanged() { protected void positionChanged() {
updateBoundingRect();
super.positionChanged(); super.positionChanged();
updateBoundingRect();
} }
@Override @Override

View File

@@ -15,6 +15,7 @@ public class EnemyData {
public boolean copyPlayerDeck = false; public boolean copyPlayerDeck = false;
public String ai; public String ai;
public boolean boss = false; public boolean boss = false;
public boolean flying = false;
public float spawnRate; public float spawnRate;
public float difficulty; public float difficulty;
public float speed; public float speed;
@@ -30,6 +31,7 @@ public class EnemyData {
deck = enemyData.deck; deck = enemyData.deck;
ai = enemyData.ai; ai = enemyData.ai;
boss = enemyData.boss; boss = enemyData.boss;
flying = enemyData.flying;
spawnRate = enemyData.spawnRate; spawnRate = enemyData.spawnRate;
copyPlayerDeck = enemyData.copyPlayerDeck; copyPlayerDeck = enemyData.copyPlayerDeck;
difficulty = enemyData.difficulty; difficulty = enemyData.difficulty;

View File

@@ -225,7 +225,16 @@ public class NewGameScene extends UIScene {
if(Forge.createNewAdventureMap) if(Forge.createNewAdventureMap)
{ {
start(); FModel.getPreferences().setPref(ForgePreferences.FPref.UI_ENABLE_MUSIC, false);
WorldSave.generateNewWorld(selectedName.getText(),
gender.getCurrentIndex() == 0,
race.getCurrentIndex(),
avatarIndex,
deck.getCurrentIndex(),
Config.instance().getConfigData().difficulties[difficulty.getCurrentIndex()],
fantasyMode, easyMode, deck.getText(), 0);
GamePlayerUtil.getGuiPlayer().setName(selectedName.getText());
Forge.switchScene(SceneType.GameScene.instance);
} }
} }

View File

@@ -82,7 +82,7 @@ public class WorldStage extends GameStage implements SaveFileContent {
enemyMoveVector.setLength(mob.speed()*delta); enemyMoveVector.setLength(mob.speed()*delta);
tempBoundingRect.set(mob.getX()+ enemyMoveVector.x,mob.getY()+ enemyMoveVector.y,mob.getWidth(),mob.getHeight()*mob.getCollisionHeight()); tempBoundingRect.set(mob.getX()+ enemyMoveVector.x,mob.getY()+ enemyMoveVector.y,mob.getWidth(),mob.getHeight()*mob.getCollisionHeight());
if(WorldSave.getCurrentSave().getWorld().collidingTile(tempBoundingRect))//if direct path is not possible if(!mob.getData().flying && WorldSave.getCurrentSave().getWorld().collidingTile(tempBoundingRect))//if direct path is not possible
{ {
tempBoundingRect.set(mob.getX()+ enemyMoveVector.x,mob.getY(),mob.getWidth(),mob.getHeight()); tempBoundingRect.set(mob.getX()+ enemyMoveVector.x,mob.getY(),mob.getWidth(),mob.getHeight());
if(WorldSave.getCurrentSave().getWorld().collidingTile(tempBoundingRect))//if only x path is not possible if(WorldSave.getCurrentSave().getWorld().collidingTile(tempBoundingRect))//if only x path is not possible
@@ -238,7 +238,7 @@ public class WorldStage extends GameStage implements SaveFileContent {
boolean enemyYIsBigger=sprite.getY()>player.getY(); boolean enemyYIsBigger=sprite.getY()>player.getY();
sprite.setX(player.getX() + spawnPos.x+(i*sprite.getWidth()*(enemyXIsBigger?1:-1)));//maybe find a better way to get spawn points sprite.setX(player.getX() + spawnPos.x+(i*sprite.getWidth()*(enemyXIsBigger?1:-1)));//maybe find a better way to get spawn points
sprite.setY(player.getY() + spawnPos.y+(i*sprite.getHeight()*(enemyYIsBigger?1:-1))); sprite.setY(player.getY() + spawnPos.y+(i*sprite.getHeight()*(enemyYIsBigger?1:-1)));
if(!WorldSave.getCurrentSave().getWorld().collidingTile(sprite.boundingRect())) if(sprite.getData().flying || !WorldSave.getCurrentSave().getWorld().collidingTile(sprite.boundingRect()))
{ {
enemies.add(Pair.of(globalTimer,sprite)); enemies.add(Pair.of(globalTimer,sprite));
foregroundSprites.addActor(sprite); foregroundSprites.addActor(sprite);

View File

@@ -18,6 +18,7 @@ public class BiomeStructure {
boolean init=false; boolean init=false;
private TextureAtlas structureAtlas; private TextureAtlas structureAtlas;
public ColorMap image; public ColorMap image;
private final static int MAXIMUM_WAVEFUNCTIONSIZE=50;
public BiomeStructure(BiomeStructureData data,long seed,int width,int height) public BiomeStructure(BiomeStructureData data,long seed,int width,int height)
{ {
@@ -59,50 +60,62 @@ public class BiomeStructure {
long currentTime = System.currentTimeMillis(); long currentTime = System.currentTimeMillis();
init=true; init=true;
OverlappingModel model= new OverlappingModel(sourceImage,data.N, (int) (data.width* biomeWidth), (int) (data.height*biomeHeight),data.periodicInput,data.periodicOutput,data.symmetry,data.ground); int targetWidth=(int) (data.width* biomeWidth);
int targetHeight=(int) (data.width* biomeWidth);
dataMap=new int[targetWidth][ targetHeight];
collisionMap=new boolean[targetWidth][ targetHeight];
ColorMap finalImage=new ColorMap(targetWidth, targetHeight);
HashMap<Integer,Integer> colorIdMap=new HashMap<>(); HashMap<Integer,Integer> colorIdMap=new HashMap<>();
for(int i=0;i<data.mappingInfo.length;i++) for(int i=0;i<data.mappingInfo.length;i++)
{ {
colorIdMap.put(Integer.parseInt(data.mappingInfo[i].color,16),i); colorIdMap.put(Integer.parseInt(data.mappingInfo[i].color,16),i);
} }
for(int mx=0;mx<targetWidth;mx+=Math.min(targetWidth-mx,MAXIMUM_WAVEFUNCTIONSIZE))
{
for(int my=0;my<targetWidth;my+=Math.min(targetHeight-my,MAXIMUM_WAVEFUNCTIONSIZE))
{
OverlappingModel model= new OverlappingModel(sourceImage,data.N,Math.min(targetWidth-mx,MAXIMUM_WAVEFUNCTIONSIZE), Math.min(targetHeight-my,MAXIMUM_WAVEFUNCTIONSIZE),data.periodicInput,data.periodicOutput,data.symmetry,data.ground);
boolean suc=false; boolean suc=false;
for(int i=0;i<10&&!suc;i++) for(int i=0;i<10&&!suc;i++)
suc=model.run((int) seed+(i*5355),0); suc=model.run((int) seed+(i*5355)+mx*my,0);
currentTime= System.currentTimeMillis();
if(!suc) if(!suc)
{ {
dataMap=new int[(int) (data.width* biomeWidth)][ (int) (data.height*biomeHeight)];
collisionMap=new boolean[(int) (data.width* biomeWidth)][ (int) (data.height*biomeHeight)];
for(int x=0;x<dataMap.length;x++) for(int x=0;x<dataMap.length;x++)
for(int y=0;y<dataMap[x].length;y++) for(int y=0;y<dataMap[x].length;y++)
dataMap[x][y]=-1; dataMap[mx+x][my+y]=-1;
return; return;
} }
image=model.graphics(); image=model.graphics();
dataMap=new int[image.getWidth()][image.getHeight()];
collisionMap=new boolean[image.getWidth()][image.getHeight()];
for(int x=0;x<image.getWidth();x++) for(int x=0;x<image.getWidth();x++)
{ {
for(int y=0;y<image.getHeight();y++) for(int y=0;y<image.getHeight();y++)
{ {
boolean isWhitePixel=maskImage!=null&&(maskImage.getColor((int) (x*maskImage.getWidth()/(float)image.getWidth()),(int)(y*(maskImage.getHeight()/(float)image.getHeight())) )).equals(Color.WHITE); boolean isWhitePixel=maskImage!=null&&(maskImage.getColor((int) ((mx+x)*maskImage.getWidth()/(float)targetWidth),(int)((my+y)*(maskImage.getHeight()/(float)targetHeight)) )).equals(Color.WHITE);
if(isWhitePixel) if(isWhitePixel)
image.setColor(x,y, Color.WHITE); finalImage.setColor(mx+x,my+y, Color.WHITE);
else
finalImage.setColor(mx+x,my+y, image.getColor(x,y));
int rgb=Color.rgb888(image.getColor(x,y)) ; int rgb=Color.rgb888(image.getColor(x,y)) ;
if(isWhitePixel||!colorIdMap.containsKey(rgb)) if(isWhitePixel||!colorIdMap.containsKey(rgb))
{ {
dataMap[x][y]=-1; dataMap[mx+x][my+y]=-1;
} }
else else
{ {
dataMap[x][y]=colorIdMap.get(rgb); dataMap[mx+x][my+y]=colorIdMap.get(rgb);
collisionMap[x][y]=data.mappingInfo[colorIdMap.get(rgb)].collision; collisionMap[mx+x][my+y]=data.mappingInfo[colorIdMap.get(rgb)].collision;
} }
} }
} }
}
image=finalImage;
}
} }
public void initialize() { public void initialize() {
initialize(sourceImage(),maskImage()); initialize(sourceImage(),maskImage());

View File

@@ -95,8 +95,8 @@
"structureAtlasPath": "world/tilesets/structures.atlas", "structureAtlasPath": "world/tilesets/structures.atlas",
"sourcePath": "world/tilesets/swamp_forest.png", "sourcePath": "world/tilesets/swamp_forest.png",
"maskPath": "world/tilesets/ring.png", "maskPath": "world/tilesets/ring.png",
"height": 0.4, "height": 0.5,
"width": 0.4, "width": 0.5,
"symmetry": 8, "symmetry": 8,
"periodicOutput": false, "periodicOutput": false,
"mappingInfo": [ "mappingInfo": [

View File

@@ -105,8 +105,8 @@
"structureAtlasPath": "world/tilesets/structures.atlas", "structureAtlasPath": "world/tilesets/structures.atlas",
"sourcePath": "world/tilesets/island_forest.png", "sourcePath": "world/tilesets/island_forest.png",
"maskPath": "world/tilesets/ring.png", "maskPath": "world/tilesets/ring.png",
"height": 0.4, "height": 0.5,
"width": 0.4, "width": 0.5,
"symmetry": 8, "symmetry": 8,
"periodicOutput": false, "periodicOutput": false,
"mappingInfo": [ "mappingInfo": [

File diff suppressed because it is too large Load Diff

View File

@@ -115,8 +115,8 @@
"structureAtlasPath": "world/tilesets/structures.atlas", "structureAtlasPath": "world/tilesets/structures.atlas",
"sourcePath": "world/tilesets/lake.png", "sourcePath": "world/tilesets/lake.png",
"maskPath": "world/tilesets/ring.png", "maskPath": "world/tilesets/ring.png",
"height": 0.4, "height": 0.5,
"width": 0.4, "width": 0.5,
"periodicOutput": false, "periodicOutput": false,
"mappingInfo": [ "mappingInfo": [
{ {

View File

@@ -108,8 +108,8 @@
"structureAtlasPath": "world/tilesets/structures.atlas", "structureAtlasPath": "world/tilesets/structures.atlas",
"sourcePath": "world/tilesets/mountain.png", "sourcePath": "world/tilesets/mountain.png",
"maskPath": "world/tilesets/ring.png", "maskPath": "world/tilesets/ring.png",
"height": 0.4, "height": 0.5,
"width": 0.4, "width": 0.5,
"periodicOutput": false, "periodicOutput": false,
"mappingInfo": [ "mappingInfo": [
{ {

View File

@@ -120,8 +120,8 @@
"structureAtlasPath": "world/tilesets/structures.atlas", "structureAtlasPath": "world/tilesets/structures.atlas",
"sourcePath": "world/tilesets/hole.png", "sourcePath": "world/tilesets/hole.png",
"maskPath": "world/tilesets/ring.png", "maskPath": "world/tilesets/ring.png",
"height": 0.3, "height": 0.5,
"width": 0.3, "width": 0.5,
"symmetry": 8, "symmetry": 8,
"periodicOutput": false, "periodicOutput": false,
"mappingInfo": [ "mappingInfo": [

View File

@@ -99,8 +99,8 @@
"structureAtlasPath": "world/tilesets/structures.atlas", "structureAtlasPath": "world/tilesets/structures.atlas",
"sourcePath": "world/tilesets/plateau.png", "sourcePath": "world/tilesets/plateau.png",
"maskPath": "world/tilesets/ring.png", "maskPath": "world/tilesets/ring.png",
"height": 0.4, "height": 0.5,
"width": 0.4, "width": 0.5,
"periodicOutput": false, "periodicOutput": false,
"mappingInfo": [ "mappingInfo": [
{ {