Skip to content

Commit

Permalink
Cam use more food targets, fixes #21
Browse files Browse the repository at this point in the history
- now if a sprite is set as food or posion it has a cusomState
    Scratch.botch --> type: "food or poison"
- save the parent md5 of each sprite, refers to #9
  • Loading branch information
raffaelepojer committed Aug 21, 2020
1 parent e9c2faa commit f924d71
Show file tree
Hide file tree
Showing 3 changed files with 165 additions and 58 deletions.
File renamed without changes.
157 changes: 116 additions & 41 deletions src/extensions/botch/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,9 @@ const BlockType = require('../../extension-support/block-type');
const Cast = require('../../util/cast');
const Organism = require('./organism');
const svgen = require('./svg-generator');
const Clone = require('../../util/clone');
const BotchStorageHelper = require('./botch-storage-helper.js');
const BotchUtil = require('./botchUtil');
const BotchUtil = require('./botch_util');
const DEFAULT_BOTCH_SPRITES = require('./default-botch-sprites.js');
const log = require('../../util/log');
const md5 = require('js-md5');
Expand All @@ -30,9 +31,6 @@ class Scratch3Botch {
// map that contains the organism <id, org> or enemies
this.organismMap = new Map();
this.enemiesMap = new Map();
// the target that represent the food or poison
this.foodTarget = {};
this.poisonTarget = {};
// default option for the new organism
this.maxForce = 0.5;
this.enemiesMaxForce = 0.3;
Expand Down Expand Up @@ -76,9 +74,18 @@ class Scratch3Botch {
}
this.organismMap = new Map();
this.enemiesMap = new Map();
this.foodTarget = {};
this.poisonTarget = {};

// check if needed
this.runtime.targets.forEach(element => {
if (!element.isStage) {
element._customState = {};
}
});
}));

// copy the custom state when clone
this._onTargetCreated = this._onTargetCreated.bind(this);
this.runtime.on('targetWasCreated', this._onTargetCreated);
}

getInfo () {
Expand Down Expand Up @@ -190,6 +197,94 @@ class Scratch3Botch {
};
}

/**
* The key to load & store a target's botch-related state.
* @type {string}
* @since botch-0.2
*/
static get STATE_KEY () {
return 'Scratch.botch';

This comment has been minimized.

Copy link
@DavidLeoni

DavidLeoni Aug 21, 2020

Member

I would call it just 'Botch'
'Scratch' prefix should be reserved for native scratch stuff, like 'Scratch.pen'

}

/**
* The default botch-related state, to be used when a target has no existing botch state.
* @type {MusicState}
* @return {BotchState} the default state
* @since botch-0-2
*/
static get DEFAULT_BOTCH_STATE () {
return {
type: 'undefined'
};
}

/**
* Food type
* @return {string} food type
* @since botch-0-2
*/
static get FOOD_TYPE () {
return 'food';
}

/**
* Poison type
* @return {string} poison type
* @since botch-0-2
*/
static get POISON_TYPE () {
return 'poison';
}

/**
* Organism type
* @return {string} organism type
* @since botch-0-2
*/
static get ORGANISM_TYPE () {
return 'organism';
}

/**
* Poison type
* @return {string} poison type
* @since botch-0-2
*/
static get ENEMY_TYPE () {
return 'enemy';
}

/**
* @param {Target} target - collect botch state for this target.
* @returns {BotchState} the mutable botch state associated with that target. This will be created if necessary.
* @since botch-0.2
*/
getBotchState (target) {
let botchState = target.getCustomState(Scratch3Botch.STATE_KEY);
if (!botchState) {
botchState = Clone.simple(Scratch3Botch.DEFAULT_BOTCH_STATE);
target.setCustomState(Scratch3Botch.STATE_KEY, botchState);
}
return botchState;
}

/**
* When a botch-target Target is cloned, clone the botch state.
* @param {Target} newTarget - the newly created target.
* @param {Target} [sourceTarget] - the target used as a source for the new clone, if any.
* @listens Runtime#event:targetWasCreated
* @private
* @since botch-0.2
*/
_onTargetCreated (newTarget, sourceTarget) {
if (sourceTarget) {
const botchState = sourceTarget.getCustomState(Scratch3Botch.STATE_KEY);
if (botchState) {
newTarget.setCustomState(Scratch3Botch.STATE_KEY, Clone.simple(botchState));
}
}
}

getSpriteMenu () {
if (this.runtime.targets.length > 1) {
return this.runtime.targets.filter(t => t.isOriginal && !t.isStage).map(t => t.getName());
Expand Down Expand Up @@ -218,21 +313,6 @@ class Scratch3Botch {
this.enemiesMap = new Map();
}
}

/**
* Check if the foodTarget or poisonTarget are already defined
* and if true, reinitialize it
* @param {string} id target id
* @since botch-0.2
*/
checkTarget (id) {
if (this.foodTarget.id === id) {
this.foodTarget = {};
}
if (this.poisonTarget === id) {
this.poisonTarget = {};
}
}

/**
* Delete all the "non original" costumes of a sprite
Expand Down Expand Up @@ -264,7 +344,6 @@ class Scratch3Botch {
util.target.id === this.enemiesMap.entries().next().value[0]) {
this.enemiesMap = new Map();
}
this.checkTarget(util.target.id);

util.target.goToFront();
this.organismMap = new Map();
Expand All @@ -283,25 +362,17 @@ class Scratch3Botch {
}
if (args.TYPE === 'food') {
this.botchUtil.deleteClones(util.target.id);
// check if it is already assigned somewhere
if (this.poisonTarget.id === util.target.id) {
this.poisonTarget = {};
}
this.checkMap(util.target.id);

util.target.setVisible(true);
this.foodTarget = util.target;

const state = this.getBotchState(util.target);
state.type = Scratch3Botch.FOOD_TYPE;
}
if (args.TYPE === 'poison') {
this.botchUtil.deleteClones(util.target.id);
// check if it is already assigned somewhere
if (this.foodTarget.id === util.target.id) {
this.foodTarget = {};
}
this.checkMap(util.target.id);

util.target.setVisible(true);
this.poisonTarget = util.target;

const state = this.getBotchState(util.target);
state.type = Scratch3Botch.POISON_TYPE;
}
if (args.TYPE === 'enemy') {
this.botchUtil.deleteClones(util.target.id);
Expand All @@ -310,13 +381,15 @@ class Scratch3Botch {
util.target.id === this.organismMap.entries().next().value[0]) {
this.organismMap = new Map();
}
this.checkTarget(util.target.id);

util.target.goToFront();
this.enemiesMap = new Map();
util.target.setVisible(true);
const enemy = new Organism(
util.target, this.mass, this.enemiesMaxForce);

const state = this.getBotchState(util.target);
state.type = Scratch3Botch.ENEMY_TYPE;

this.enemiesMap.set(util.target.id, enemy);
enemy.assignEnemyCostume();
Expand Down Expand Up @@ -353,7 +426,8 @@ class Scratch3Botch {
const stageH = this.runtime.constructor.STAGE_HEIGHT;
newClone.setXY((Math.random() - 0.5) * stageW, (Math.random() - 0.5) * stageH);
}
this.storeSprite(newClone.id);
const p = this.storeSprite(newClone.id);
newClone.setCustomState('storedMd5', p.md5);
}
}

Expand Down Expand Up @@ -458,7 +532,7 @@ class Scratch3Botch {
const org = this.organismMap.get(util.target.id);
if (!org.target.isOriginal) { // Only the clones are managed
if (org.health > 0) {
org.stepOrganism(this.foodTarget, this.poisonTarget, this.enemiesMap);
org.stepOrganism(this.enemiesMap);

const newOrg = org.clone();
if (newOrg !== null) { // if it create a child
Expand All @@ -468,9 +542,10 @@ class Scratch3Botch {
newClone.clearEffects();
newOrg.target = newClone; // assign the new target to new organism
}
newOrg.setParentVariable(org.target.id);
const p = this.storeSprite(newClone.id);
newClone.setCustomState('storedMd5', p.md5);
newOrg.setParentVariable(org.target.getCustomState('storedMd5'));
this.organismMap.set(newClone.id, newOrg);
this.storeSprite(newClone.id);
}
}

Expand Down
66 changes: 49 additions & 17 deletions src/extensions/botch/organism.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ if (typeof TextEncoder === 'undefined') {
const Vector2 = require('./vector2');
const MathUtil = require('../../util/math-util');
const svgen = require('./svg-generator');
const BotchUtil = require('./botchUtil');
const BotchUtil = require('./botch_util');

/**
* @since botch-0.1
Expand Down Expand Up @@ -104,17 +104,15 @@ class Organism {

/**
* Compute the step needed to move
* @param {RenderedTarget} foodTarget foodTarget
* @param {RenderedTarget} poisonTarget poisonTarget
* @param {Map} enemiesMap enemiesMap
* @since botch-0.2
*/
stepOrganism (foodTarget, poisonTarget, enemiesMap) {
stepOrganism (enemiesMap) {
this.boundaries(
this.runtime.constructor.STAGE_WIDTH,
this.runtime.constructor.STAGE_HEIGHT);
this.refreshArgs(this.mass, this.maxForce);
this.behaveGeneralOrganism(foodTarget, poisonTarget, enemiesMap);
this.behaveGeneralOrganism(enemiesMap);
this.update();
this.breathe();
}
Expand Down Expand Up @@ -166,26 +164,60 @@ class Organism {
this.maxForce = parseFloat(maxForce_);
}

/**
* Get all the food target
* @returns {Array} food targets
* @since botch-0.2
*/
getFoodTarget () {
if (this.runtime.targets.length > 0) {
return this.runtime.targets.filter(t => {
if (!t.isStage) {
const state = t.getCustomState('Scratch.botch');
if (state && state.type === 'food') {
return true;
}
}
return false;
});
}
}

/**
* Get all the poison target
* @returns {Array} poison targets
* @since botch-0.2
*/
getPoisonTarget () {
if (this.runtime.targets.length > 0) {
return this.runtime.targets.filter(t => {
if (!t.isStage) {
const state = t.getCustomState('Scratch.botch');
if (state && state.type === 'poison') {
return true;
}
}
return false;
});
}
}

/**
* General behaviour for organism
* @param {RenderedTarget} foodTarget foodTarget
* @param {RenderedTarget} poisonTarget poisonTarget
* @param {Map<string, Organism>} enemiesMap enemies map
* @since botch-0.2
*/
behaveGeneralOrganism (foodTarget, poisonTarget, enemiesMap) {
behaveGeneralOrganism (enemiesMap) {
let steerG = new Vector2(0, 0);
let steerB = new Vector2(0, 0);
let steerE = new Vector2(0, 0);
if (foodTarget.hasOwnProperty('sprite')) {
steerG = this.eatGeneral(foodTarget, 0.2, this.dna[2]);
}
if (poisonTarget.hasOwnProperty('sprite')) {
steerB = this.eatGeneral(poisonTarget, -0.5, this.dna[3]);
}
steerG = this.eatGeneral(this.getFoodTarget(), 0.2, this.dna[2]);
steerB = this.eatGeneral(this.getPoisonTarget(), -0.5, this.dna[3]);

if (enemiesMap && enemiesMap.size > 0) {
steerE = this.eatGeneral(enemiesMap, 0, this.dna[4]);
}

steerG.mult(this.dna[0]);
steerB.mult(this.dna[1]);
steerE.mult(this.dna[5]);
Expand Down Expand Up @@ -257,10 +289,10 @@ class Organism {
const stageH = this.target.runtime.constructor.STAGE_HEIGHT;
const esc = 30;

if (agent.hasOwnProperty('sprite')) { // with food and poison
if (agent.length > 0 && agent[0].hasOwnProperty('sprite')) { // with food and poison
// get all the clones
const all = agent.sprite.clones;
all.forEach(element => {
// const all = agent.sprite.clones;
agent.forEach(element => {
const d = new Vector2(element.x, element.y).dist(new Vector2(this.target.x, this.target.y));

// If is close to food (eat) change the position if is original
Expand Down

0 comments on commit f924d71

Please sign in to comment.