LibGDX - Multiple actors receiving key events - input

I have more than one actor (for a local coop game) that need to receive key events (e.g. Player 1 uses arrow keys, Player 2 uses WASD etc...). If I just add Actors to a Stage, they don't receive key events through the InputListener, and if I do this:
stage.setKeyboardFocus(p1);
stage.setKeyboardFocus(p2);
Only Player 2 receives key events, of course. How can I have two (or more) actors receive key events?

You can use a Group or a Table which are actors that can contain other actors, and add the actors
Gdx.setInputProcessor(stage);
group = new Group();
group.addActor(actor1);
group.addActor(actor2);
group.addListener(new InputListener(){
#Override
public boolean keyDown(InputEvent event, int keycode){
if (keycode == Keys.A){
update(actor1)
}
if (keycode == Keys.LEFT{
update(actor2)
}
return true;
});
stage.addActor(group);
stage.setKeyboardFocus(group);

Libgdx Stage extends InputAdapter, which gives you access to the methods keyDown(int keyCode) and keyUp(int keyCode). If you set the Stage as your InputProcessor by using: Gdx.setInputProcessor(stage); you can handle key inputs in the Stage.
Some Pseudocode:
public boolean keyDown(int keyCode) {
switch (keyCode) {
case Input.Keys.A:
player2.moveLeft();
case Input.Keys.NUMPAD_4:
player1.moveLeft();
}
}
Hope it helps.

It's curious that nobody mentioned InputMultiplexer. Try it for your situation.

Figured it out. Instead of setting the keyboard focus to the individual Actors, set it to a common actor, and then just add a listener to that actor. E.G.:
public class Scene extends Stage
{
public Scene()
{
setKeyboardFocus(getRoot()); // getRoot() returns the parent actor group
addActor(new Player(1));
addActor(new Player(2));
}
}
public class Player extends Actor
{
public Player(Stage stage)
{
stage.getRoot().addListener(inputListener);
}
}

Related

How to create actor with parameterized constructor from testprobe

I am trying test to MyActor for sending a MessageB to itself on condition. MyActor takes setting as constructor parameter. Setting doesn't have setter cause it is intended to be immutable after creation.
public class MyActor : ReceiveActor
{
private bool Setting { get; }
public MyActor(bool setting)
{
Setting = setting;
Receive<MessageA>(message => HandleMessageA(message));
}
public void HandleMessageA(MessageA message)
{
if (Setting)
Self.Tell(new MessageB);
}
}
And here is the test
[Test]
public void HandleMessageA_SettingIsTrue_MessageBIsSent()
{
bool setting = true;
var testProbe = this.CreateTestProbe();
var myActor = Props.Create<MyActor>(testProbbe);
myActor.Tell(new MessageA);
myActor.ExpectMsg<MessageB>();
}
My problem is that i don't know how to pass bool setting to constructor.
Well I can write it like this
bool setting = true;
var myActor = Props.Create<MyActor>(setting);
And this way myActor will have settings set. But than I didn't use TestProbe and therefore will not be able to listen for expected message. So my question is how make Arrange section of test correctly?
A great guide to testing with Akka.NET describes how to create actors within the test system:
Create your actors within Sys so that your actors exist in the same
ActorSystem as the TestActor.
// create an actor in the TestActorSystem
var actor = Sys.ActorOf(Props.Create(() => new MyActorClass()));
Well the situation you have created is rather artificial. Because in a real world scenario you would either send MessageB to another actor. Which you would then be able to substitute with a TestProbe. Or you would verify the sideeffect that your messageB would have. So for example sending messageB to Self, would update some property on your actor, which you could then Test for.
Also see Chima's response, he shows the correct way to create your actor. Because only instantiating the Props is not enough.
And some general advice. When testing actors, you will want to try to refrain from testing for individual messages. Try and test the outcome (or side-effect) of sending those messages instead. That way your tests are a lot less brittle should you ever refactor your Actor's interactions

How to handle a stale akka.net remote iactorref

I am using remote actors in a akka.net in a windows service that stays up long term. I obtain an IActorRef for the remote actor using ActorSelection and I keep this IActorRef alive for an extended period of time in the service. The IActorRef points to an actor system running in another windows service.
I understand that a restart of the remote actor will not invalidate the remote actor ref. However, it is conceivable that the remote windows service might get restarted at some point and the IActorRef in the calling windows service would become invalid.
What is the best practice for handling this?
A naive approach would be to use ActorSelection to obtain a new IActorRef every time I want to make a call to the remote actor. This would obviously be inefficient.
Another approach might be to simply wrap every call I make on that IActorRef in some kind of error handling envelope that traps exceptions and obtains a new IActorRef using actorselection and retries? Or the envelope might make a test call before every actual call to see if the remote actor is still alive and if not get a new actor ref.
Any better way?
Default option for detecting dead actors is to Watch them (see documentation). When one actor watches another, it will receive Terminated message, once watched actor becomes dead or unreachable.
Watching for a Terminated message will alert a system that a remote actor has died, but there is a question of how exactly to respond to a terminated remote actor. Assuming that an actor obtains an IActorRef to a remote actor via its constructor, how would the actor obtain a new IActorRef to the remote actor when it becomes alive again. One way would be to have the actor fail and delegate to parent actor which would then obtain a new IActorRef to the remote actor via actor selection. The problem with this, however, is that the original actor selection for the remote actor might have taken place in non-actor code in a composition root where dependency injection normally would occur. I suppose you could get around this by passing a actor selection factory delegate around which could be used to reconstruct the remote IActorRef. An alternative that I came up with is to create a wrapper class that implements IActorRef called FaultTolerantActorRef.
This class takes the path of the remote (or local) actor in the constructor and periodically does an actor selection to get a refresh IActorRef to the remote actor. This way if for some reason the remote actor dies calls on the FaultTolerantActorRef will end up in dead letters while the remote actor is dead. However, when the remote actor eventually comes on line again, calls to the FaultTolerantActorRef will eventually reach the newly revived remote actor without having to take any explicit action on the part of the calling local actor.
There is an Invalidate method which will force the FaultTolerantActorRef to do a fresh actor selection on the next call. This could presumebly be called by an actor in response to a Terminated message from the remote actor. Even without calling Invalidate, a fresh actor selection will occur based on the refresh interval passed to the constructor.
using Akka.Actor;
using System;
using Akka.Util;
using System.Threading;
namespace JA.AkkaCore
{
public class FaultTolerantActorRef : IActorRef
{
public IActorRef ActorRef
{
get
{
if (!_valid || DateTime.Now.Ticks > Interlocked.Read(ref _nextRefreshTime))
RefreshActorRef();
return _actorRef;
}
}
public ActorPath Path
{
get
{
return ActorRef.Path;
}
}
object _lock = new object();
IActorRef _actorRef;
volatile bool _valid;
string _path;
IActorRefFactory _actorSystem;
private TimeSpan _requestTimeout;
private TimeSpan _refreshInterval;
//private DateTime _nextRefreshTime = DateTime.MinValue;
private long _nextRefreshTime = DateTime.MinValue.Ticks;
public FaultTolerantActorRef(IActorRefFactory actorSystem, IActorRef actorRef,
TimeSpan refreshInterval = default(TimeSpan), TimeSpan requestTimeout = default(TimeSpan))
: this(actorSystem, actorRef.Path.ToString(), refreshInterval, requestTimeout)
{
_actorRef = actorRef;
_valid = true;
}
public FaultTolerantActorRef(IActorRefFactory actorSystem, string actorPath,
TimeSpan refreshInterval = default(TimeSpan), TimeSpan requestTimeout = default(TimeSpan))
{
if (refreshInterval == default(TimeSpan))
_refreshInterval = TimeSpan.FromSeconds(60);
else
_refreshInterval = refreshInterval;
if (requestTimeout == default(TimeSpan))
_requestTimeout = TimeSpan.FromSeconds(60);
else
_requestTimeout = requestTimeout;
_actorSystem = actorSystem;
_valid = false;
_path = actorPath;
}
private void RefreshActorRef()
{
lock(_lock)
{
if (!_valid || DateTime.Now.Ticks > _nextRefreshTime)
{
_actorRef = _actorSystem.ActorSelectionOne(_path, _requestTimeout);
Interlocked.Exchange(ref _nextRefreshTime,DateTime.Now.Ticks + _refreshInterval.Ticks);
_valid = true;
}
}
}
public void Invalidate()
{
_valid = false;
}
public void Tell(object message, IActorRef sender)
{
ActorRef.Tell(message, sender);
}
public bool Equals(IActorRef other)
{
return ActorRef.Equals(other);
}
public int CompareTo(IActorRef other)
{
return ActorRef.CompareTo(other);
}
public ISurrogate ToSurrogate(ActorSystem system)
{
return ActorRef.ToSurrogate(system);
}
public int CompareTo(object obj)
{
return ActorRef.CompareTo(obj);
}
}
}

nullPointerException error greenfoot

I'm working on a project for an intro to programming class, and I've run into a slight problem. We're making a side scroller, and I'm working on the score counter right now. My issue is that when I try to create a reference to the counter class in anything other than the act method(called once every frame) I get a null pointer exception error. You can download the zip file with my code in it here if you want to take a look.
EDIT:
Here's the offending code:
public class HeroMissile extends Missiles
{
/**
* Act - do whatever the HeroMissile wants to do. This method is called whenever
* the 'Act' or 'Run' button gets pressed in the environment.
*/
public void act()
{
move(8);
remove();
}
public void remove() {
if(isTouching(Drone.class)) {
removeTouching(Drone.class);
getWorld().addObject(new Explosion(), getX(), getY());
getWorld().removeObject(this);
addScore();
return;
}
}
public void addScore() {
City cityWorld = (City) getWorld();
**Counter scoreCounter = cityWorld.getCounter();**
scoreCounter.add(1);
}
}
You are calling getWorld() [in addScore()] after you removed yourself from the world. In this case, getWorld() will return null, so you will get a null pointer exception. Try changing the order in remove() to add the score before you remove yourself from the world.

Google Play Services - Sending A Rematch Request

After a multiplayer game is over, is there any possibility of sending a rematch request to the same participants?
Note that this is not provided by the Google API, I am wondering if people have any ideas on implementing such a system.
Thanks,
Rajat
If you just want a solution to inviting all the same people from the previous game.. this works for the player that initiated that initiated the game:
When you get back the Intent from selecting the players.. just save it:
// Handle the result of the "Select players UI" we launched when the user clicked the
// "Invite friends" button. We react by creating a room with those players.
private void handleSelectPlayersResult(int response, Intent data) {
if (response != Activity.RESULT_OK) {
Log.w(TAG, "*** select players UI cancelled, " + response);
Gdx.app.postRunnable(new Runnable() {
#Override
public void run() {
mGHInterface.onBackedOut();
}
});
return;
}
Log.d(TAG, "Select players UI succeeded.");
previousMatch = data;
// get the invitee list ...(etc, etc)
Then, whatever way you want to activate the next bit of code works:
#Override
public void sendOutRematch() {
handleSelectPlayersResult(Activity.RESULT_OK, previousMatch);
}
Now, for players that are invited to the room... need to look at the Room object for them, and get the invited player id's from that object.. and save that list of players so it can be used in the Room Creation process with something like this to grab the ids :
ArrayList<String> playerIDs;
for (Participant p : room.getParticipants()) {
playerIDs.add(p.getPlayer().getPlayerId());
}
then use that list in your room creation process.

Asynchronous callback - gwt

I am using gwt and postgres for my project. On the front end i have few widgets whose data i am trying to save on to tables at the back-end when i click on "save project" button(this also takes the name for the created project).
In the asynchronous callback part i am setting more than one table. But it is not sending the data properly. I am getting the following error:
org.postgresql.util.PSQLException: ERROR: insert or update on table "entitytype" violates foreign key constraint "entitytype_pname_fkey"
Detail: Key (pname)=(Project Name) is not present in table "project".
But when i do the select statement on project table i can see that the project name is present.
Here is how the callback part looks like:
oksave.addClickHandler(new ClickHandler(){
#Override
public void onClick(ClickEvent event) {
if(erasync == null)
erasync = GWT.create(EntityRelationService.class);
AsyncCallback<Void> callback = new AsyncCallback<Void>(){
#Override
public void onFailure(Throwable caught) {
}
#Override
public void onSuccess(Void result){ }
};
erasync.setProjects(projectname, callback);
for(int i = 0; i < boundaryPanel.getWidgetCount(); i++){
top = new Integer(boundaryPanel.getWidget(i).getAbsoluteTop()).toString();
left = new Integer(boundaryPanel.getWidget(i).getAbsoluteLeft()).toString();
if(widgetTitle.startsWith("ATTR")){
type = "regular";
erasync.setEntityAttribute(name1, name, type, top, left, projectname, callback);
} else{
erasync.setEntityType(name, top, left, projectname, callback);
}
}
}
Question:
Is it wrong to set more than one in the asynchronous callback where all the other tables are dependent on a particular table?
when i say setProjects in the above code isn't it first completed and then moved on to the next one?
Please any input will be greatly appreciated.
Thank you.
With that foreign key constraint, you must make sure the erasync.setProjects(...) has completed before you insert the rest of the stuff.
I suggest doing the erasync.setEntityAttribute(...) magic in (or from) an onsuccess callback instead of jumping right to it.
You're firing several request in which (guessing from the error message) really should be called in sequence.
Any time you call more than one rpc call; try to think that you should be able to rearrange them in any order (because that's allmost what actually happens because they're asynchronous)... If running them in reverse order does not make sense; you cannot fire them sequentially!
Two ways to fix your problem:
Nesting:
service.callFirst(someData, new AsyncCallback<Void> callback = new AsyncCallback<Void>(){
#Override
public void onFailure(Throwable caught) {/*Handle errors*/}
#Override
public void onSuccess(Void result){
service.callSecond(someOtherData, new AsyncCallback<Void> callback = new AsyncCallback<Void>(){
/* onSuccess and onFailure for second callback here */
});
}
});
Or creating one service call that does both (Recommended):
service.callFirstAndSecond(someData, someOtherData, new AsyncCallback<Void> callback = new AsyncCallback<Void>(){
#Override
public void onFailure(Throwable caught) {/*Handle errors*/}
#Override
public void onSuccess(Void result){
/* Handle success */
}
});
The second option is most likely going to be much less messy, as several nested asynch callbacks quickly grows quite wide and confusing, also you make just one request.
Because of nature of Async, don't assume setProjects(...) method will be called on the server before setEntityAttribute or setEntityType.
Personally, I prefer to have a Project class which contains all necessary info, for example:
public class Project{
private String projectName;
private List attributes = new ArrayList();
.. other properties
// Getter & Setter methods
}
Then send to the server in one round trip:
Project project = new Project();
project.setProjectName(..);
// Set other properties
erasync.saveProjects(project, callback);