diff --git a/.idea/.name b/.idea/.name
deleted file mode 100644
index 419372801c8..00000000000
--- a/.idea/.name
+++ /dev/null
@@ -1 +0,0 @@
-Catroid
\ No newline at end of file
diff --git a/.idea/codeStyles/Project.xml b/.idea/codeStyles/Project.xml
index 24cd8c6e312..874d47a4e60 100644
--- a/.idea/codeStyles/Project.xml
+++ b/.idea/codeStyles/Project.xml
@@ -6,6 +6,7 @@
+
diff --git a/catroid/src/androidTest/java/org/catrobat/catroid/test/content/actions/GlideToTouchPositionActionTest.kt b/catroid/src/androidTest/java/org/catrobat/catroid/test/content/actions/GlideToTouchPositionActionTest.kt
new file mode 100644
index 00000000000..a45c845a81b
--- /dev/null
+++ b/catroid/src/androidTest/java/org/catrobat/catroid/test/content/actions/GlideToTouchPositionActionTest.kt
@@ -0,0 +1,110 @@
+/*
+ * Catroid: An on-device visual programming system for Android devices
+ * Copyright (C) 2010-2026 The Catrobat Team
+ * ()
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * An additional term exception under section 7 of the GNU Affero
+ * General Public License, version 3, is available at
+ * http://developer.catrobat.org/license_additional_term
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see .
+ */
+
+package org.catrobat.catroid.test.content.actions
+
+import com.badlogic.gdx.scenes.scene2d.actions.SequenceAction
+import org.catrobat.catroid.ProjectManager
+import org.catrobat.catroid.common.BrickValues
+import org.catrobat.catroid.common.ScreenValues
+import org.catrobat.catroid.content.Project
+import org.catrobat.catroid.content.Scene
+import org.catrobat.catroid.content.Sprite
+import org.catrobat.catroid.content.actions.GlideToTouchPositionAction
+import org.catrobat.catroid.formulaeditor.Formula
+import org.junit.Assert.assertEquals
+import org.junit.Assert.assertNotEquals
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+
+
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+import org.catrobat.catroid.utils.TouchUtil
+import org.koin.java.KoinJavaComponent
+
+@RunWith(AndroidJUnit4::class)
+class GlideToTouchPositionActionTest {
+
+ private lateinit var sprite: Sprite
+ private lateinit var action: GlideToTouchPositionAction
+ private val EXPECTED_X_POSITION =20f;
+ private val EXPECTED_Y_POSITION =40f;
+ private val projectManager: ProjectManager by KoinJavaComponent.inject(ProjectManager::class.java)
+
+ @Before
+ @Throws(Exception::class)
+ fun SetUp() {
+
+
+ val project = Project()
+ projectManager.currentProject = project
+ val scene = Scene()
+ project.addScene(scene)
+ projectManager.currentlyPlayingScene = scene
+ sprite = Sprite("testSprite")
+ scene.addSprite(sprite)
+ ScreenValues.setToDefaultScreenSize()
+ action = sprite.actionFactory.createGlideToPositionAction(
+ sprite, null, SequenceAction(), Formula(2.0),
+ BrickValues.GLIDE_TO_TOUCH_POSITION
+ )
+ as GlideToTouchPositionAction
+ }
+
+ @Test
+ public fun testGlideToTouchPositionDestination() {
+
+ sprite.look.xInUserInterfaceDimensionUnit = 0f
+ sprite.look.yInUserInterfaceDimensionUnit = 0f
+
+ assertEquals(0f, sprite.look.xInUserInterfaceDimensionUnit)
+ assertEquals(0f, sprite.look.yInUserInterfaceDimensionUnit)
+
+ TouchUtil.touchDown(EXPECTED_X_POSITION, EXPECTED_Y_POSITION, 0)
+
+ action.act(2.0F)
+
+ assertEquals(EXPECTED_Y_POSITION, sprite.look.yInUserInterfaceDimensionUnit)
+ assertEquals(EXPECTED_X_POSITION, sprite.look.xInUserInterfaceDimensionUnit)
+ }
+
+ @Test
+ public fun testGlideToBehavior(){
+ sprite.look.xInUserInterfaceDimensionUnit = 0f
+ sprite.look.yInUserInterfaceDimensionUnit = 0f
+
+ assertEquals(0f, sprite.look.xInUserInterfaceDimensionUnit)
+ assertEquals(0f, sprite.look.yInUserInterfaceDimensionUnit)
+
+ TouchUtil.touchDown(EXPECTED_X_POSITION, EXPECTED_Y_POSITION, 0)
+ action.act(1.0f)
+
+ assertNotEquals(0f, sprite.look.xInUserInterfaceDimensionUnit)
+ assertNotEquals(0f, sprite.look.yInUserInterfaceDimensionUnit)
+ assertNotEquals(EXPECTED_X_POSITION, sprite.look.xInUserInterfaceDimensionUnit)
+ assertNotEquals(EXPECTED_Y_POSITION, sprite.look.yInUserInterfaceDimensionUnit)
+ assertEquals(action.currentXPosition, sprite.look.xInUserInterfaceDimensionUnit)
+ assertEquals(action.currentYPosition, sprite.look.yInUserInterfaceDimensionUnit)
+ }
+}
diff --git a/catroid/src/main/java/org/catrobat/catroid/common/BrickValues.java b/catroid/src/main/java/org/catrobat/catroid/common/BrickValues.java
index 2c3e8901757..5361d7c1c4d 100644
--- a/catroid/src/main/java/org/catrobat/catroid/common/BrickValues.java
+++ b/catroid/src/main/java/org/catrobat/catroid/common/BrickValues.java
@@ -67,6 +67,10 @@ public final class BrickValues {
public static final int GO_TO_TOUCH_POSITION = 80;
public static final int GO_TO_RANDOM_POSITION = 81;
public static final int GO_TO_OTHER_SPRITE_POSITION = 82;
+ public static final int GLIDE_TO_TOUCH_POSITION = 1;
+ public static final int GLIDE_TO_RANDOM_POSITION = 0;
+ public static final int GLIDE_TO_OTHER_SPRITE_POSITION = 2;
+
public static final int SET_LOOK_BY_INDEX = 1;
public static final String PARTICLE_COLOR = "#ff0000";
diff --git a/catroid/src/main/java/org/catrobat/catroid/content/ActionFactory.java b/catroid/src/main/java/org/catrobat/catroid/content/ActionFactory.java
index bf57365f012..25e9290a19a 100644
--- a/catroid/src/main/java/org/catrobat/catroid/content/ActionFactory.java
+++ b/catroid/src/main/java/org/catrobat/catroid/content/ActionFactory.java
@@ -68,7 +68,10 @@
import org.catrobat.catroid.content.actions.FlashAction;
import org.catrobat.catroid.content.actions.ForItemInUserListAction;
import org.catrobat.catroid.content.actions.ForVariableFromToAction;
+import org.catrobat.catroid.content.actions.GlideToOtherSpritePositionAction;
import org.catrobat.catroid.content.actions.GlideToPhysicsAction;
+import org.catrobat.catroid.content.actions.GlideToRandomPositionAction;
+import org.catrobat.catroid.content.actions.GlideToTouchPositionAction;
import org.catrobat.catroid.content.actions.GoNStepsBackAction;
import org.catrobat.catroid.content.actions.GoThroughAction;
import org.catrobat.catroid.content.actions.GoToOtherSpritePositionAction;
@@ -206,6 +209,7 @@
import org.catrobat.catroid.content.bricks.brickspinner.PickableDrum;
import org.catrobat.catroid.content.bricks.brickspinner.PickableMusicalInstrument;
import org.catrobat.catroid.formulaeditor.Formula;
+import org.catrobat.catroid.formulaeditor.InterpretationException;
import org.catrobat.catroid.formulaeditor.UserData;
import org.catrobat.catroid.formulaeditor.UserList;
import org.catrobat.catroid.formulaeditor.UserVariable;
@@ -375,6 +379,35 @@ public Action createGlideToAction(Sprite sprite, SequenceAction sequence, Formul
return action;
}
+ public Action createGlideToPositionAction(Sprite sprite,
+ Sprite destinationSprite, SequenceAction sequence,
+ Formula duration, int spinnerSelection) throws InterpretationException {
+ Scope scope = new Scope(ProjectManager.getInstance().getCurrentProject(), sprite, sequence);
+ switch (spinnerSelection) {
+ case BrickValues.GLIDE_TO_RANDOM_POSITION:
+ GlideToRandomPositionAction randomAction =
+ action(GlideToRandomPositionAction.class);
+ randomAction.setScope(scope);
+ randomAction.setDuration(duration.interpretFloat(scope));
+ return randomAction;
+ case BrickValues.GLIDE_TO_TOUCH_POSITION:
+ GlideToTouchPositionAction touchAction =
+ action(GlideToTouchPositionAction.class);
+ touchAction.setScope(scope);
+ touchAction.setDuration(duration.interpretFloat(scope));
+ return touchAction;
+ case BrickValues.GLIDE_TO_OTHER_SPRITE_POSITION:
+ GlideToOtherSpritePositionAction otherSpritePositionAction =
+ action(GlideToOtherSpritePositionAction.class);
+ otherSpritePositionAction.setScope(scope);
+ otherSpritePositionAction.setDuration(duration.interpretFloat(scope));
+ otherSpritePositionAction.setDestinationSprite(destinationSprite);
+ return otherSpritePositionAction;
+ default:
+ return null;
+ }
+ }
+
public Action createPlaceAtAction(Sprite sprite, SequenceAction sequence, Formula x, Formula y) {
GlideToAction action = Actions.action(GlideToAction.class);
action.setPosition(x, y);
@@ -609,7 +642,6 @@ public Action createStopEngraveAction(Sprite sprite) {
return action;
}
-
public Action createStartCutAction(Sprite sprite) {
StartCutAction action = Actions.action(StartCutAction.class);
action.setSprite(sprite);
@@ -1232,14 +1264,15 @@ public Action createWriteEmbroideryToFileAction(Sprite sprite, SequenceAction se
return action;
}
- public Action createSavePlotAction(Sprite sprite, SequenceAction sequence, Formula fileName){
+ public Action createSavePlotAction(Sprite sprite, SequenceAction sequence, Formula fileName) {
SavePlotAction action = Actions.action(SavePlotAction.class);
Scope scope = new Scope(ProjectManager.getInstance().getCurrentProject(), sprite, sequence);
action.setScope(scope);
action.setFormula(fileName);
return action;
}
- public Action createSaveLaserAction(Sprite sprite, SequenceAction sequence, Formula fileName){
+
+ public Action createSaveLaserAction(Sprite sprite, SequenceAction sequence, Formula fileName) {
SaveLaserAction action = Actions.action(SaveLaserAction.class);
Scope scope = new Scope(ProjectManager.getInstance().getCurrentProject(), sprite, sequence);
action.setScope(scope);
@@ -1247,14 +1280,15 @@ public Action createSaveLaserAction(Sprite sprite, SequenceAction sequence, Form
return action;
}
- public Action createSharePlotAction(Sprite sprite, SequenceAction sequence, Formula fileName){
+ public Action createSharePlotAction(Sprite sprite, SequenceAction sequence, Formula fileName) {
SharePlotAction action = Actions.action(SharePlotAction.class);
Scope scope = new Scope(ProjectManager.getInstance().getCurrentProject(), sprite, sequence);
action.setScope(scope);
action.setFormula(fileName);
return action;
}
- public Action createShareLaserAction(Sprite sprite, SequenceAction sequence, Formula fileName){
+
+ public Action createShareLaserAction(Sprite sprite, SequenceAction sequence, Formula fileName) {
ShareLaserAction action = Actions.action(ShareLaserAction.class);
Scope scope = new Scope(ProjectManager.getInstance().getCurrentProject(), sprite, sequence);
action.setScope(scope);
@@ -1540,7 +1574,7 @@ public Action createAssertUserListsAction(Sprite sprite, SequenceAction sequence
}
public Action createRepeatParameterizedAction(Sprite sprite, ParameterizedData data,
- List extends Pair> parameters,
+ List> parameters,
String position, Action repeatedAction, boolean isLoopDelay) {
RepeatParameterizedAction action = action(RepeatParameterizedAction.class);
action.setParameterizedData(data);
diff --git a/catroid/src/main/java/org/catrobat/catroid/content/Scope.kt b/catroid/src/main/java/org/catrobat/catroid/content/Scope.kt
index ca8f35a736b..12cb25e770d 100644
--- a/catroid/src/main/java/org/catrobat/catroid/content/Scope.kt
+++ b/catroid/src/main/java/org/catrobat/catroid/content/Scope.kt
@@ -27,6 +27,6 @@ import com.badlogic.gdx.scenes.scene2d.actions.SequenceAction
data class Scope(
val project: Project?,
- val sprite: Sprite,
+ var sprite: Sprite,
val sequence: SequenceAction?
)
diff --git a/catroid/src/main/java/org/catrobat/catroid/content/actions/GlideToOtherSpritePositionAction.kt b/catroid/src/main/java/org/catrobat/catroid/content/actions/GlideToOtherSpritePositionAction.kt
new file mode 100644
index 00000000000..2153e00f1fc
--- /dev/null
+++ b/catroid/src/main/java/org/catrobat/catroid/content/actions/GlideToOtherSpritePositionAction.kt
@@ -0,0 +1,64 @@
+/*
+ * Catroid: An on-device visual programming system for Android devices
+ * Copyright (C) 2010-2025 The Catrobat Team
+ * ()
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * An additional term exception under section 7 of the GNU Affero
+ * General Public License, version 3, is available at
+ * http://developer.catrobat.org/license_additional_term
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see .
+ */
+package org.catrobat.catroid.content.actions
+
+import com.badlogic.gdx.scenes.scene2d.actions.TemporalAction
+import org.catrobat.catroid.content.Scope
+import org.catrobat.catroid.content.Sprite
+
+class GlideToOtherSpritePositionAction : TemporalAction() {
+ lateinit var scope: Scope
+ var destinationSprite: Sprite? = null
+ private var startXPosition: Float = 0f
+ private var startYPosition: Float = 0f
+ var destinationXPosition: Float = 0f
+ var destinationYPosition: Float = 0f
+ var currentXPosition: Float = 0f
+ var currentYPosition: Float = 0f
+
+
+ override fun begin() {
+ super.begin()
+ scope.sprite.isGliding = true
+ startXPosition = scope.sprite.look.xInUserInterfaceDimensionUnit
+ startYPosition = scope.sprite.look.yInUserInterfaceDimensionUnit
+ }
+
+ override fun act(delta: Float): Boolean {
+ return super.act(delta)
+
+ }
+ override fun update(percent: Float) {
+ val destinationLook = destinationSprite?.look?:return
+ destinationXPosition = destinationLook.xInUserInterfaceDimensionUnit
+ destinationYPosition = destinationLook.yInUserInterfaceDimensionUnit
+ currentXPosition = startXPosition + (destinationXPosition-startXPosition)*percent
+ currentYPosition = startYPosition + (destinationYPosition-startYPosition)*percent
+ scope.sprite.look?.setPositionInUserInterfaceDimensionUnit(currentXPosition,currentYPosition)
+ }
+ override fun end(){
+ super.end()
+ scope.sprite.isGliding = false
+ }
+
+}
diff --git a/catroid/src/main/java/org/catrobat/catroid/content/actions/GlideToRandomPositionAction.kt b/catroid/src/main/java/org/catrobat/catroid/content/actions/GlideToRandomPositionAction.kt
new file mode 100644
index 00000000000..00d051121c2
--- /dev/null
+++ b/catroid/src/main/java/org/catrobat/catroid/content/actions/GlideToRandomPositionAction.kt
@@ -0,0 +1,62 @@
+/*
+ * Catroid: An on-device visual programming system for Android devices
+ * Copyright (C) 2010-2025 The Catrobat Team
+ * ()
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * An additional term exception under section 7 of the GNU Affero
+ * General Public License, version 3, is available at
+ * http://developer.catrobat.org/license_additional_term
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see .
+ */
+package org.catrobat.catroid.content.actions
+
+import com.badlogic.gdx.scenes.scene2d.actions.TemporalAction
+import org.catrobat.catroid.common.ScreenValues
+import org.catrobat.catroid.content.Scope
+
+
+class GlideToRandomPositionAction : TemporalAction() {
+ lateinit var scope: Scope
+ private var startXPosition: Float = 0f
+ private var startYPosition: Float = 0f
+ var randomXPosition: Float = 0f
+ var randomYPosition: Float = 0f
+ var currentXPosition: Float = 0f
+ var currentYPosition: Float = 0f
+
+
+ override fun begin() {
+ super.begin()
+ scope.sprite.isGliding = true
+ startXPosition = scope.sprite.look.xInUserInterfaceDimensionUnit
+ startYPosition = scope.sprite.look.yInUserInterfaceDimensionUnit
+ randomXPosition = Math.random().toFloat() * (ScreenValues.currentScreenResolution.width +
+ 1) - (ScreenValues.currentScreenResolution.width / 2)
+ randomYPosition = Math.random().toFloat() * (ScreenValues.currentScreenResolution.height +
+ 1) - (ScreenValues.currentScreenResolution.height / 2)
+ }
+
+ override fun update(percent: Float) {
+
+ currentXPosition = startXPosition + (randomXPosition-startXPosition)*percent
+ currentYPosition = startYPosition + (randomYPosition-startYPosition)*percent
+ scope.sprite.look?.setPositionInUserInterfaceDimensionUnit(currentXPosition,currentYPosition)
+ }
+ override fun end(){
+ super.end()
+ scope.sprite.isGliding = false
+ }
+
+}
diff --git a/catroid/src/main/java/org/catrobat/catroid/content/actions/GlideToTouchPositionAction.kt b/catroid/src/main/java/org/catrobat/catroid/content/actions/GlideToTouchPositionAction.kt
new file mode 100644
index 00000000000..ba35c15a189
--- /dev/null
+++ b/catroid/src/main/java/org/catrobat/catroid/content/actions/GlideToTouchPositionAction.kt
@@ -0,0 +1,70 @@
+/*
+* Catroid: An on-device visual programming system for Android devices
+* Copyright (C) 2010-2025 The Catrobat Team
+* ()
+*
+* This program is free software: you can redistribute it and/or modify
+* it under the terms of the GNU Affero General Public License as
+* published by the Free Software Foundation, either version 3 of the
+* License, or (at your option) any later version.
+*
+* An additional term exception under section 7 of the GNU Affero
+* General Public License, version 3, is available at
+* http://developer.catrobat.org/license_additional_term
+*
+* This program is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU Affero General Public License for more details.
+*
+* You should have received a copy of the GNU Affero General Public License
+* along with this program. If not, see .
+*/
+package org.catrobat.catroid.content.actions
+
+import com.badlogic.gdx.scenes.scene2d.actions.TemporalAction
+import org.catrobat.catroid.content.Scope
+import org.catrobat.catroid.utils.TouchUtil
+
+class GlideToTouchPositionAction : TemporalAction() {
+ lateinit var scope: Scope
+ private var startXPosition: Float = 0f
+ private var startYPosition: Float = 0f
+ var touchXPosition: Float = 0f
+ var touchYPosition: Float = 0f
+ var touchIndex: Int = 0
+ var currentXPosition: Float = 0f
+ var currentYPosition: Float = 0f
+ var touchFound = false
+
+ override fun begin() {
+ super.begin()
+ scope.sprite.isGliding = true
+ startXPosition = scope.sprite.look.xInUserInterfaceDimensionUnit
+ startYPosition = scope.sprite.look.yInUserInterfaceDimensionUnit
+ }
+
+ override fun act(delta: Float): Boolean {
+ if (!touchFound){
+ touchIndex = TouchUtil.getLastTouchIndex()
+ if(touchIndex > 0 && TouchUtil.isFingerTouching(touchIndex)){
+ touchFound = true
+ touchXPosition = TouchUtil.getX(touchIndex)
+ touchYPosition = TouchUtil.getY(touchIndex)
+ return super.act(delta)
+ }
+ return false
+ }
+ return super.act(delta)
+ }
+ override fun update(percent: Float) {
+
+ currentXPosition = startXPosition + (touchXPosition-startXPosition)*percent
+ currentYPosition = startYPosition + (touchYPosition-startYPosition)*percent
+ scope.sprite.look?.setPositionInUserInterfaceDimensionUnit(currentXPosition,currentYPosition)
+ }
+ override fun end(){
+ super.end()
+ scope.sprite.isGliding = false
+ }
+}
diff --git a/catroid/src/main/java/org/catrobat/catroid/content/bricks/GlideToPositionBrick.kt b/catroid/src/main/java/org/catrobat/catroid/content/bricks/GlideToPositionBrick.kt
new file mode 100644
index 00000000000..825d27734f9
--- /dev/null
+++ b/catroid/src/main/java/org/catrobat/catroid/content/bricks/GlideToPositionBrick.kt
@@ -0,0 +1,134 @@
+/*
+ * Catroid: An on-device visual programming system for Android devices
+ * Copyright (C) 2010-2026 The Catrobat Team
+ * ()
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * An additional term exception under section 7 of the GNU Affero
+ * General Public License, version 3, is available at
+ * http://developer.catrobat.org/license_additional_term
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see .
+ */
+
+package org.catrobat.catroid.content.bricks
+
+import android.content.Context
+import android.view.View
+import org.catrobat.catroid.ProjectManager
+import org.catrobat.catroid.R
+import org.catrobat.catroid.common.BrickValues
+import org.catrobat.catroid.common.Nameable
+import org.catrobat.catroid.content.Sprite
+import org.catrobat.catroid.content.actions.ScriptSequenceAction
+import org.catrobat.catroid.content.bricks.Brick.BrickField
+import org.catrobat.catroid.content.bricks.brickspinner.BrickSpinner
+import org.catrobat.catroid.content.bricks.brickspinner.StringOption
+import org.catrobat.catroid.formulaeditor.Formula
+import org.koin.java.KoinJavaComponent
+
+class GlideToPositionBrick(var destinationSprite: Sprite? = null) : FormulaBrick(), BrickSpinner
+.OnItemSelectedListener {
+ private var spinnerSelection: Int = 0
+
+ init {
+ addAllowedBrickField(
+ BrickField.DURATION_IN_SECONDS,
+ R.id.brick_glide_to_position_edit_text_duration
+
+ )
+ }
+
+ constructor(durationInMilliSecondsValue: Int) : this() {
+ val durationInSeconds = durationInMilliSecondsValue / 1000.0
+ setFormulaWithBrickField(BrickField.DURATION_IN_SECONDS, Formula(durationInSeconds))
+ }
+
+ override fun getViewResource(): Int {
+ return R.layout.brick_glide_to_position
+ }
+
+ override fun getDefaultBrickField(): BrickField {
+ return BrickField.DURATION_IN_SECONDS
+ }
+
+ override fun getView(context: Context?): View? {
+ super.getView(context)
+ val projectManager = KoinJavaComponent.get(ProjectManager::class.java)
+ setSecondsLabel(view, BrickField.DURATION_IN_SECONDS)
+ val items: MutableList = ArrayList()
+ items.add(StringOption(context!!.getString(R.string.brick_glide_to_random_position)))
+ items.add(StringOption(context.getString(R.string.brick_glide_to_touch_position)))
+ items.addAll(projectManager.currentlyEditedScene.spriteList)
+ items.remove(projectManager.currentlyEditedScene.backgroundSprite)
+ items.remove(projectManager.currentSprite)
+ val spinner: BrickSpinner = BrickSpinner(
+ R.id
+ .brick_glide_to_position_spinner,
+ view, items
+ )
+ spinner.setOnItemSelectedListener(this)
+
+ if (spinnerSelection == BrickValues.GLIDE_TO_RANDOM_POSITION) {
+ spinner.setSelection(0)
+ }
+ if (spinnerSelection == BrickValues.GLIDE_TO_TOUCH_POSITION) {
+ spinner.setSelection(1)
+ }
+ if (spinnerSelection == BrickValues.GLIDE_TO_OTHER_SPRITE_POSITION) {
+ spinner.setSelection(destinationSprite)
+ }
+ return view
+ }
+
+ override fun onNewOptionSelected(spinnerId: Int?) {
+ //is needed
+ }
+
+ override fun onEditOptionSelected(spinnerId: Int?) {
+ //is needed
+ }
+
+ override fun onStringOptionSelected(spinnerId: Int?, string: String) {
+ val context = view.context
+
+ if (string == context.getString(R.string.brick_glide_to_touch_position)) {
+ spinnerSelection = BrickValues.GLIDE_TO_TOUCH_POSITION
+ destinationSprite = null
+ }
+
+ if (string == context.getString(R.string.brick_glide_to_random_position)) {
+ spinnerSelection = BrickValues.GLIDE_TO_RANDOM_POSITION
+ destinationSprite = null
+ }
+ }
+
+ override fun onItemSelected(spinnerId: Int?, item: Sprite?) {
+ spinnerSelection = BrickValues.GLIDE_TO_OTHER_SPRITE_POSITION
+ destinationSprite = item
+ }
+
+ override fun addActionToSequence(sprite: Sprite, sequence: ScriptSequenceAction) {
+ sequence.addAction(
+ sprite.actionFactory.createGlideToPositionAction(
+ sprite, destinationSprite, sequence,
+ getFormulaWithBrickField(BrickField.DURATION_IN_SECONDS), spinnerSelection
+ )
+ )
+ }
+
+ companion object {
+ @Suppress("unused")
+ private const val serialVersionUID = 1L
+ }
+}
diff --git a/catroid/src/main/java/org/catrobat/catroid/ui/fragment/CategoryBricksFactory.kt b/catroid/src/main/java/org/catrobat/catroid/ui/fragment/CategoryBricksFactory.kt
index 78424807e2f..f0d8ec13af9 100644
--- a/catroid/src/main/java/org/catrobat/catroid/ui/fragment/CategoryBricksFactory.kt
+++ b/catroid/src/main/java/org/catrobat/catroid/ui/fragment/CategoryBricksFactory.kt
@@ -27,6 +27,7 @@ import org.catrobat.catroid.BuildConfig
import org.catrobat.catroid.ProjectManager
import org.catrobat.catroid.R
import org.catrobat.catroid.common.BrickValues
+import org.catrobat.catroid.common.BrickValues.GLIDE_SECONDS
import org.catrobat.catroid.content.BroadcastScript
import org.catrobat.catroid.content.RaspiInterruptScript
import org.catrobat.catroid.content.WhenBounceOffScript
@@ -87,6 +88,7 @@ import org.catrobat.catroid.content.bricks.ForItemInUserListBrick
import org.catrobat.catroid.content.bricks.ForVariableFromToBrick
import org.catrobat.catroid.content.bricks.ForeverBrick
import org.catrobat.catroid.content.bricks.GlideToBrick
+import org.catrobat.catroid.content.bricks.GlideToPositionBrick
import org.catrobat.catroid.content.bricks.GoNStepsBackBrick
import org.catrobat.catroid.content.bricks.GoToBrick
import org.catrobat.catroid.content.bricks.GoThroughBrick
@@ -477,9 +479,9 @@ open class CategoryBricksFactory {
GlideToBrick(
BrickValues.X_POSITION,
BrickValues.Y_POSITION,
- BrickValues.GLIDE_SECONDS
- )
+ GLIDE_SECONDS)
)
+ motionBrickList.add(GlideToPositionBrick(GLIDE_SECONDS))
if (!isBackgroundSprite) {
motionBrickList.add(GoNStepsBackBrick(BrickValues.GO_BACK))
motionBrickList.add(ComeToFrontBrick())
diff --git a/catroid/src/main/res/layout/brick_glide_to_position.xml b/catroid/src/main/res/layout/brick_glide_to_position.xml
new file mode 100644
index 00000000000..b4d6807bce0
--- /dev/null
+++ b/catroid/src/main/res/layout/brick_glide_to_position.xml
@@ -0,0 +1,75 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/catroid/src/main/res/values/strings.xml b/catroid/src/main/res/values/strings.xml
index fb9bc873e2d..85a58a44063 100644
--- a/catroid/src/main/res/values/strings.xml
+++ b/catroid/src/main/res/values/strings.xml
@@ -1007,6 +1007,8 @@
Go totouch positionrandom position
+ touch position
+ random position
diff --git a/catroid/src/test/java/org/catrobat/catroid/test/content/actions/GlideToOtherSpritePositionActionTest.kt b/catroid/src/test/java/org/catrobat/catroid/test/content/actions/GlideToOtherSpritePositionActionTest.kt
new file mode 100644
index 00000000000..e5548980e0d
--- /dev/null
+++ b/catroid/src/test/java/org/catrobat/catroid/test/content/actions/GlideToOtherSpritePositionActionTest.kt
@@ -0,0 +1,125 @@
+/*
+ * Catroid: An on-device visual programming system for Android devices
+ * Copyright (C) 2010-2025 The Catrobat Team
+ * ()
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * An additional term exception under section 7 of the GNU Affero
+ * General Public License, version 3, is available at
+ * http://developer.catrobat.org/license_additional_term
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see .
+ */
+package org.catrobat.catroid.test.content.actions
+
+import com.badlogic.gdx.scenes.scene2d.actions.SequenceAction
+import org.catrobat.catroid.ProjectManager
+import org.catrobat.catroid.common.BrickValues
+import org.catrobat.catroid.common.ScreenValues
+import org.catrobat.catroid.content.Project
+import org.catrobat.catroid.content.Scene
+import org.catrobat.catroid.content.Sprite
+import org.catrobat.catroid.content.actions.GlideToOtherSpritePositionAction
+import org.catrobat.catroid.formulaeditor.Formula
+import org.junit.After
+import org.junit.Assert.assertEquals
+import org.junit.Assert.assertNotEquals
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.JUnit4
+import org.koin.core.context.startKoin
+import org.koin.core.context.stopKoin
+import org.koin.dsl.module
+
+@RunWith(JUnit4::class)
+class GlideToOtherSpritePositionActionTest {
+ private lateinit var sprite: Sprite
+ private lateinit var destinationSprite: Sprite
+ private lateinit var action: GlideToOtherSpritePositionAction
+
+ companion object {
+ private const val DESTINATION_X_POSITION = 150f
+ private const val DESTINATION_Y_POSITION = 300f
+ }
+
+ private lateinit var projectManager: ProjectManager
+
+ @Before
+ @Throws(Exception::class)
+ fun setUp() {
+ stopKoin()
+ val mockContext = org.mockito.Mockito.mock(android.content.Context::class.java)
+ projectManager = ProjectManager(mockContext)
+ val project = Project()
+ projectManager.currentProject = project
+ startKoin {
+ modules(module {
+ single { projectManager }
+ single {
+ org.mockito.Mockito.mock(
+ org.catrobat.catroid.utils
+ .MobileServiceAvailability::class.java
+ )
+ }
+ })
+ }
+ val scene = Scene()
+ project.addScene(scene)
+ projectManager.currentlyPlayingScene = scene
+ sprite = Sprite("testSprite")
+ destinationSprite = Sprite("destinationSprite")
+ scene.addSprite(sprite)
+ scene.addSprite(destinationSprite)
+ ScreenValues.setToDefaultScreenSize()
+ action = sprite.actionFactory.createGlideToPositionAction(
+ sprite, destinationSprite,
+ SequenceAction(), Formula(2.0F), BrickValues.GLIDE_TO_OTHER_SPRITE_POSITION
+ ) as GlideToOtherSpritePositionAction
+ }
+
+ @After
+ fun tearDown(){
+ stopKoin()
+ }
+
+ @Test
+ fun testGlideToOtherSpritePositionAction() {
+ destinationSprite.look.xInUserInterfaceDimensionUnit = DESTINATION_X_POSITION
+ destinationSprite.look.yInUserInterfaceDimensionUnit = DESTINATION_Y_POSITION
+ sprite.look.xInUserInterfaceDimensionUnit = 0f
+ sprite.look.yInUserInterfaceDimensionUnit = 0f
+ assertEquals(0f, sprite.look.xInUserInterfaceDimensionUnit)
+ assertEquals(0f, sprite.look.yInUserInterfaceDimensionUnit)
+ action.act(2f)
+ assertEquals(DESTINATION_X_POSITION, sprite.look.xInUserInterfaceDimensionUnit)
+ assertEquals(DESTINATION_Y_POSITION, sprite.look.yInUserInterfaceDimensionUnit)
+ }
+
+ @Test
+ fun testGlideToBehavior() {
+ destinationSprite.look.xInUserInterfaceDimensionUnit = DESTINATION_X_POSITION
+ destinationSprite.look.yInUserInterfaceDimensionUnit = DESTINATION_Y_POSITION
+ sprite.look.xInUserInterfaceDimensionUnit = 0f
+ sprite.look.yInUserInterfaceDimensionUnit = 0f
+ assertEquals(0f, sprite.look.xInUserInterfaceDimensionUnit)
+ assertEquals(0f, sprite.look.yInUserInterfaceDimensionUnit)
+ action.act(1f)
+ assertNotEquals(0f, sprite.look.xInUserInterfaceDimensionUnit)
+ assertNotEquals(0f, sprite.look.yInUserInterfaceDimensionUnit)
+ assertNotEquals(DESTINATION_X_POSITION, sprite.look.xInUserInterfaceDimensionUnit)
+ assertNotEquals(DESTINATION_Y_POSITION, sprite.look.yInUserInterfaceDimensionUnit)
+ assertEquals(action.currentXPosition, sprite.look.xInUserInterfaceDimensionUnit)
+ assertEquals(action.currentYPosition, sprite.look.yInUserInterfaceDimensionUnit)
+ }
+}
diff --git a/catroid/src/test/java/org/catrobat/catroid/test/content/actions/GlideToRandomPositionActionTest.kt b/catroid/src/test/java/org/catrobat/catroid/test/content/actions/GlideToRandomPositionActionTest.kt
new file mode 100644
index 00000000000..29db746d188
--- /dev/null
+++ b/catroid/src/test/java/org/catrobat/catroid/test/content/actions/GlideToRandomPositionActionTest.kt
@@ -0,0 +1,130 @@
+/*
+ * Catroid: An on-device visual programming system for Android devices
+ * Copyright (C) 2010-2026 The Catrobat Team
+ * ()
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * An additional term exception under section 7 of the GNU Affero
+ * General Public License, version 3, is available at
+ * http://developer.catrobat.org/license_additional_term
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see .
+ */
+
+package org.catrobat.catroid.test.content.actions
+
+import android.widget.Spinner
+import com.badlogic.gdx.scenes.scene2d.actions.SequenceAction
+import org.catrobat.catroid.ProjectManager
+import org.catrobat.catroid.common.BrickValues
+import org.catrobat.catroid.common.ScreenValues
+import org.catrobat.catroid.content.Project
+import org.catrobat.catroid.content.Scene
+import org.catrobat.catroid.content.Sprite
+import org.catrobat.catroid.content.actions.GlideToRandomPositionAction
+import org.catrobat.catroid.formulaeditor.Formula
+import org.junit.After
+import org.junit.Assert.assertEquals
+import org.junit.Assert.assertNotEquals
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.JUnit4
+import org.koin.core.context.startKoin
+import org.koin.core.context.stopKoin
+import org.koin.core.scope.Scope
+import org.koin.dsl.module
+import org.koin.ext.scope
+
+import kotlin.getValue
+import kotlin.time.Duration
+import org.koin.java.KoinJavaComponent
+
+
+@RunWith(JUnit4::class)
+class GlideToRandomPositionActionTest {
+
+ private lateinit var sprite: Sprite
+ private lateinit var dummySprite: Sprite
+ private lateinit var action: GlideToRandomPositionAction
+ private lateinit var projectManager: ProjectManager
+
+ @Before
+ @Throws(Exception::class)
+ fun SetUp() {
+ stopKoin()
+ val mockContext = org.mockito.Mockito.mock(android.content.Context::class.java)
+ projectManager = ProjectManager(mockContext)
+ val project = Project()
+ projectManager.currentProject = project
+ startKoin {
+ modules(module {
+ single { projectManager }
+ single {
+ org.mockito.Mockito.mock(
+ org.catrobat.catroid.utils
+ .MobileServiceAvailability::class.java
+ )
+ }
+ })}
+ val scene = Scene()
+ project.addScene(scene)
+ projectManager.currentlyPlayingScene = scene
+ sprite = Sprite("testSprite")
+ dummySprite = Sprite("dummySprite")
+ scene.addSprite(sprite)
+ ScreenValues.setToDefaultScreenSize()
+ action = sprite.actionFactory.createGlideToPositionAction(
+ sprite, dummySprite, SequenceAction(), Formula(2.0),
+ BrickValues.GLIDE_TO_RANDOM_POSITION
+ )
+ as GlideToRandomPositionAction
+ }
+ @After
+ fun tearDown(){
+ stopKoin()
+ }
+
+ @Test
+ fun testGlideToRandomPositionDestination() {
+
+ sprite.look.xInUserInterfaceDimensionUnit = 0f
+ sprite.look.yInUserInterfaceDimensionUnit = 0f
+
+ assertEquals(0f, sprite.look.xInUserInterfaceDimensionUnit)
+ assertEquals(0f, sprite.look.yInUserInterfaceDimensionUnit)
+
+ action.act(2.0F)
+
+ assertEquals(action.randomYPosition, sprite.look.yInUserInterfaceDimensionUnit)
+ assertEquals(action.randomXPosition, sprite.look.xInUserInterfaceDimensionUnit)
+ }
+
+ @Test
+ fun testGlideToBehavior(){
+ sprite.look.xInUserInterfaceDimensionUnit = 0f
+ sprite.look.yInUserInterfaceDimensionUnit = 0f
+
+ assertEquals(0f, sprite.look.xInUserInterfaceDimensionUnit)
+ assertEquals(0f, sprite.look.yInUserInterfaceDimensionUnit)
+
+ action.act(1.0f)
+
+ assertNotEquals(0f, sprite.look.xInUserInterfaceDimensionUnit)
+ assertNotEquals(0f, sprite.look.yInUserInterfaceDimensionUnit)
+ assertNotEquals(action.randomXPosition, sprite.look.xInUserInterfaceDimensionUnit)
+ assertNotEquals(action.randomYPosition, sprite.look.yInUserInterfaceDimensionUnit)
+ assertEquals(action.currentXPosition, sprite.look.xInUserInterfaceDimensionUnit)
+ assertEquals(action.currentYPosition, sprite.look.yInUserInterfaceDimensionUnit)
+ }
+}
diff --git a/catroid/src/test/java/org/catrobat/catroid/test/content/actions/GoToRandomPositionActionTest.kt b/catroid/src/test/java/org/catrobat/catroid/test/content/actions/GoToRandomPositionActionTest.kt
index 81f2477e121..e1de830b99e 100644
--- a/catroid/src/test/java/org/catrobat/catroid/test/content/actions/GoToRandomPositionActionTest.kt
+++ b/catroid/src/test/java/org/catrobat/catroid/test/content/actions/GoToRandomPositionActionTest.kt
@@ -53,7 +53,7 @@ class GoToRandomPositionActionTest {
}
@Test
- fun testGoToOtherSpriteAction() {
+ fun testGoToRandomPositionAction() {
sprite.look.xInUserInterfaceDimensionUnit = 0f
sprite.look.yInUserInterfaceDimensionUnit = 0f
diff --git a/gradle/gradle-daemon-jvm.properties b/gradle/gradle-daemon-jvm.properties
new file mode 100644
index 00000000000..baa28d154c6
--- /dev/null
+++ b/gradle/gradle-daemon-jvm.properties
@@ -0,0 +1,13 @@
+#This file is generated by updateDaemonJvm
+toolchainUrl.FREE_BSD.AARCH64=https\://api.foojay.io/disco/v3.0/ids/491f83666ae7f4d6ebb28fee72ebb035/redirect
+toolchainUrl.FREE_BSD.X86_64=https\://api.foojay.io/disco/v3.0/ids/0d1a1acdc708062093673f65aa9aba4b/redirect
+toolchainUrl.LINUX.AARCH64=https\://api.foojay.io/disco/v3.0/ids/491f83666ae7f4d6ebb28fee72ebb035/redirect
+toolchainUrl.LINUX.X86_64=https\://api.foojay.io/disco/v3.0/ids/0d1a1acdc708062093673f65aa9aba4b/redirect
+toolchainUrl.MAC_OS.AARCH64=https\://api.foojay.io/disco/v3.0/ids/7083b89563e7ce20943037b8cd2b8cc2/redirect
+toolchainUrl.MAC_OS.X86_64=https\://api.foojay.io/disco/v3.0/ids/060bbb778a1f55ea705fdebd2ccfeab9/redirect
+toolchainUrl.UNIX.AARCH64=https\://api.foojay.io/disco/v3.0/ids/491f83666ae7f4d6ebb28fee72ebb035/redirect
+toolchainUrl.UNIX.X86_64=https\://api.foojay.io/disco/v3.0/ids/0d1a1acdc708062093673f65aa9aba4b/redirect
+toolchainUrl.WINDOWS.AARCH64=https\://api.foojay.io/disco/v3.0/ids/d09679dc60fe5aa05ef7d03efdefac20/redirect
+toolchainUrl.WINDOWS.X86_64=https\://api.foojay.io/disco/v3.0/ids/ed4e3bf2f5e7c5d9aabc4cbd8acd555e/redirect
+toolchainVendor=JETBRAINS
+toolchainVersion=21