How to detect a Long press in a game with flutter/flame - flutter

I have a rect appearing in the game and I am able to detect taps like this
in main.dart
TapGestureRecognizer tapper = TapGestureRecognizer();
tapper.onTapDown = game.onTapDown;
flameUtil.addGestureRecognizer(tapper);
in game-controller.dart
void onTapDown(TapDownDetails d) {
if (mainMenu.tutorialBtnRect.contains(d.globalPosition)) {
mainMenu.tutorialTapped();
}
}
I can't seem to be able to get it to work with any of the LongPressGestures
Something about PrimaryButton and velocity I am not able to set
Please help
Thanks

It is easier to not use the GestureRecognizers and just implement it directly on your game.
class MyGame extends BaseGame with LongPressDetector {
MyGame();
#override
void onLongPressEnd(LongPressEndDetails details) {
if (mainMenu.tutorialBtnRect.contains(details.globalPosition)) {
mainMenu.tutorialTapped();
}
}
}

Related

Update touch position (slide) during time with Flame (Flutter)

in my game with Flame I have a space ship, and I want it to follow where I'm pressing with my finger. For the moment it goes to the first spot I touch until I leave the finger from the screen, but if I move keeping it on, it continues to follow where I initially pressed. Is there a way to update where my finger is(using HasTappableComponents)? Or should I change approach?
class SpaceFlame extends FlameGame with HasTappableComponents {
late Ship ship;
late TapHandler tapHandler;
#override
Future<void> onLoad() async {
ship = Ship()
..position = Vector2(size.x / 2, size.y / 2)
..size = Vector2(64, 64)
..setSpeed(100);
tapHandler = TapHandler();
ship.anchor = Anchor.center;
await addAll([
Background(Palette.background),
ship,
tapHandler,
]);
}
#override
void render(Canvas canvas) {
canvas.drawRect(canvasSize.toRect(), Paint()..color = Palette.buttonBlu);
}
#override
void update(double dt) {
// TODO: implement update
if (tapHandler.tapped) {
print('tapped');
Vector2 moveDirection = Vector2(
tapHandler.tapPosition.x - ship.position.x,
tapHandler.tapPosition.y - ship.position.y);
ship.setMoveDirection(moveDirection);
} else {
ship.setMoveDirection(Vector2.zero());
}
super.update(dt);
}
}
class TapHandler extends PositionComponent with TapCallbacks {
TapHandler() : super(anchor: Anchor.center);
bool tapped = false;
Vector2 _tapPosition = Vector2.zero();
final _paint = Paint()..color = const Color(0x00000000);
#override
void onGameResize(Vector2 canvasSize) {
super.onGameResize(canvasSize);
size = canvasSize;
position = canvasSize / 2;
}
Vector2 get tapPosition => _tapPosition;
#override
void render(Canvas canvas) {
canvas.drawRect(size.toRect(), _paint);
}
#override
void onTapDown(TapDownEvent event) {
print('object');
tapped = true;
_tapPosition = event.canvasPosition;
}
}
When you keep your finger on the screen and drag it the even is no longer a tap, but a drag.
To react to this event you need to use HasDraggableComponents on the game and DragCallbacks on the component. Then you need to implement onDragUpdate in your component and set the position to the position that the event reports for the drag.

How to simulate a mouse up event?

There is a bug in my code: When I release the mouse out of the screen, the unity can't detect "GetMouseButtonUp", and when I move the released mouse back to the screen, it detects the "GetMouseButton" which should not.
So when the mouse out of the screen, I want simulate send a mouse up event to let the unity detect "GetMouseButtonUp".
How to simulate a mouse event?
Pseudo code
bool mouseIsDown = false;
public void Update()
{
Rect screenRect = new Rect(-Screen.width/2, -Screen.height/2, Screen.width, Screen.height);
If(screenRect.Contains(Input.mousePosition))
{
if(mouseIsDown && !Input.GetMouseButton(0))
OnMouseUp();
if(Input.GetMouseButton(0))
{
OnMouse();
if(!mouseIsDown)
{
OnMouseDown();
mouseIsDown = true;
}
}
}
}
public void OnMouseDown()
{
// Do something
}
public void OnMouse()
{
// Do something
}
public void OnMouseUp()
{
// Do something
}
I am not sure if I correctly understand your question. But, you can use these functions the same way you would use the Start() Update() Awake() etc. functions
void OnMouseUp () {
}
void OnMouseDown (){
}

Wait function on Unity

I want to wait until "next" button is pressed then continue
child.addChild(tmp);
childrenAdded.Push(tmp);
neighbor.GetComponent.<Renderer>().material.mainTexture = null;
-WAIT UNTIL CLICK ON NEXT BUTTON THEN CONTINUE-
toExpand.Push(tmp);
any idea? I tried:
while(true) {
if(GUI.Button(Rect(500,680 ,100,30),"Next"))
break
}
But it doesn't work; it freezes.
Instead of waiting, you can just have your code called when the button is clicked, like this:
void OnGUI() {
if(GUI.Button(Rect(500,680 ,100,30),"Next"))
toExpand.Push(tmp);
}
}
If possible, consider using Unity 4.6 or later so you can use the new UI which is much easier work with.
You can use Toggle button instead of button so you controll a boolean with toogle and loops what you need in your Update or LateUpdate function like this:
private Rect myRect = new Rect(500,680 ,100,30);
private bool myToggle = false;
void OnGui() {
myToggle = GUI.Toogle(myRect, myToggle, "Next");
}
void Update() {
if(myToggle){
// what I need to create while true;
}
}
Note that is not a good practice to create a new Rect every OnGUI cycle because it runs more than once per frame and it will create a performance issue.
Reading your code again may I could've misinterpreted your needing so if you could clarify what you really what your code to do would be easier to help.
Also, if you just need a "wizard" like sequence of actions I suggest you to take a look on delegates and use something like this:
delegate void MyDelegate();
private MyDelegate myDelegate;
private Rect myRect = new Rect(500,680 ,100,30);
void Start () {
myDelegate = FirstFunction;
}
void FirstFunction() {
// will execute until next button is clicked
}
void SecondFunction() {
// will execute after next button is clicked
}
void OnGui() {
if(GUI.Button(myRect, "Next")) {
myDelegate = SecondFunction;
}
}

Adding a button to MediaController

I want to add a button to MediaController. So I extended MediaController class, created a button and added it into the frame layout. But the newly added button is not reflecting while running.
Please find the code below
public class VideoController extends MediaController {
private Button searchButton;
public VideoController(Context context) {
super(context);
searchButton = new Button(context);
searchButton.setText("Search");
FrameLayout.LayoutParams params = new FrameLayout.LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
params.gravity = Gravity.RIGHT;
System.out.println("Adding a button");
addView(searchButton, params);
//updateViewLayout(this, params);
}
#Override
public void hide() {
}
}
what I am doing wrong here. Any suggestions will be helpful.
Thanks in advance.
You have to override setAnchorView in your VideoController class:
#Override
public void setAnchorView(View view) {
super.setAnchorView(view);
Button searchButton = new Button(context);
searchButton.setText("Search");
FrameLayout.LayoutParams params = new FrameLayout.LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
params.gravity = Gravity.RIGHT;
addView(searchButton, params);
}
Actually that happens because media controller's view is constructed later (in makeControllerView method). So you need to override it and add button there.
Unfortunately, it is hidden at the moment. And overriding setAnchorView seems the best solution.

Preserving object after a reload scene

In a scene of my quiz game I have an animation object that changes for another animation when a button to move to the next question is pressed (the button reload the scene). I would like to keep the animation, the last animation referenced to the object, after the scene is reloaded, but I don't know how. The object always returns to its normal state (the first animation).
I currently have a script called 'tower' referenced to the object where I make a static object and a DontDestroyOnLoad function:
public static SpriteRenderer towerAnimation;
void Awake()
{
DontDestroyOnLoad(gameObject);
towerAnimation = GetComponent<SpriteRenderer>();
}
And this code in the Update of 'GameManager' script:
public static int counterQuestionChances = 2;
void DestroyTower()
{
if (counterQuestionChances == 1)
{
Tower.towerAnimation.SetTrigger("error 1");
}
else
{
if (counterQuestionChances == 0)
{
Tower.towerAnimation.SetTrigger("error 2");
}
}
But it doesn't work. I'm taking shots in the dark because I don't know how to solve this. I'd appreciate if you could give me any ideas that can help me with this. Thanks!
You're going to have to use the SceneManagement library that Unity has so when the scene changes the method below called OnActiveSceneChanged gets called.
using UnityEngine.SceneManagement;
public class Tower : MonoBehaviour
{
public static SpriteRenderer towerAnimation;
public int storedCounter = 0;
void Awake()
{
DontDestroyOnLoad(gameObject);
towerAnimation = GetComponent<SpriteRenderer>();
SceneManager.activeSceneChanged += OnActiveSceneChanged;
}
private void OnActiveSceneChanged(UnityEngine.SceneManagement.Scene scene, UnityEngine.SceneManagement.Scene currentScene)
{
//tower animation stuff here
}
}