I am making a simple game, and every second, I need the player to lose a food "point". Currently, I have the declaration like so.
var timer = NSTimer.scheduledTimerWithTimeInterval(1.0, target: player, selector: Selector(player.foodLoss()), userInfo: nil, repeats: true)
And I never hear from the timer again, it has, to the best of my knowledge, no effect on the rest of the app. My Player class is as follows
class Player: Character {
var food = 100
init(startingHealth: Int = 100, startingFood: Int = 100) {
super.init(imageNamed: "Player", entityName: "Player")
food = startingFood
sprite = SKSpriteNode(imageNamed: "Player")
}
func adjustFood(amountToAdjustBy adjustAmount: Int) -> Bool{
if food + adjustAmount <= 100 {
food += adjustAmount
return true
} else {
return false
}
}
func foodLoss() {
food -= 1
print("food lost")
}
}
I get no error when running the code. The only thing that happens is player.food is completely unaffected. Any help with my problem would be very helpful.
Thanks in advance!
You need to change the selector. Right now you would actually call the method foodLoss when creating the timer and use the return value (Void) as the method the timer should call all the time. It therefore will not do anything.
To fix that you need to provide a different selector. For example use Selector("foodLoss") instead:
var timer = NSTimer.scheduledTimerWithTimeInterval(1.0, target: player, selector: Selector("foodLoss"), userInfo: nil, repeats: true)
To make that work you might have to mark the foodLoss function as #objc:
#objc func foodLoss() {
food -= 1
print("food lost")
}
Related
I'm currently trying to solve a programming problem using minimax with alpha-beta-pruning.
The game is represented as a tree with a defined root. Each node has a given cost. Each node can have an amount of childs bigger than 0 if its not a leaf. The game has to end at a leaf.
Player A wants to maximize the cost he can receive by traversing the tree. He can choose to stay at the current node, or go to one of its childs.
Player B wants to minimize the cost, but he has to choose a child and can't pass unlike Player A.
Both Players play optimally.
I have implemented a solution, which does return the desired results, but is too slow after a certain amount of nodes, leading to a timeout.
My idea would be to somehow save the results of the previous minimax search for the given tree, but that only helps if Player A chooses to advance, otherwise I would have to do the minimax search again.
vector<int> edges[MAXN];
int minimax(int node, bool p1_turn, int alpha, int beta) {
if(edges[node].empty()) return cost[node];
if(p1_turn) {
int best = minimax(node, false, alpha, beta);
for(auto u: edges[node]) {
int val = minimax(u, false, alpha, beta);
best = max(val, best);
alpha = max(alpha, best);
if(beta <= alpha) {
break;
}
}
return best;
} else {
int best = MAX_INF;
for(auto u: edges[node]){
int val = minimax(u, true, alpha, beta);
best = min(best, val);
beta = min(best, beta);
if(beta <= alpha){
break;
}
}
return best;
}
}
...
minimax(1, true, MIN_INF, MAX_INF)
...
Applying the above algorithm returns the desired results, but is too slow after a certain amount of nodes.
EDIT
Changed the inner if-block to be more in line with https://en.wikipedia.org/wiki/Alpha%E2%80%93beta_pruning#Pseudocode
if(edges[node].empty()) return cost[node];
if(p1_turn) {
int best = minimax(node, false, alpha, beta);
for(auto u: edges[node]) {
best = max(best, minimax(u, false, alpha, beta));
if(best > beta) {
break;
}
alpha = max(alpha, best);
}
return best;
} else {
int best = MAX_INF;
for(auto u: edges[node]){
best = min(best, minimax(u, true, alpha, beta));
if(best < alpha){
break;
}
beta = min(best, beta);
}
return best;
}
I'm currently developing a meta tic tac toe AI to play against in Unity. I would like to instantiate particles whenever the player plays a move. However, the particles freeze when the AI's move evaluation function is called. What is the simplest way to make the particles continue to move while the computer is calculating the best move? I've read documentation about unity Job system, but Job structs can't contain reference types which, here is a problem.
public void Play (List<Move> moves) {
int[,] grid = gB.stateGrid;
Move bestMove = new Move();
if (firstTurn)
{
bestMove.col = 4;
bestMove.row = 4;
firstTurn = false;
}
else
{
foreach (Move m in moves)
{
int e = EvalMove(m, level, true, grid, gB.subgridsStates, Mathf.NegativeInfinity, Mathf.Infinity);
m.value = e;
}
int best = moves.Select(x => x.value).Max();
List<Move> bestMoves = moves.Where(x => x.value == best).ToList();
bestMove = bestMoves[Random.Range(0, bestMoves.Count - 1)];
}
gB.PlaceToken(bestMove);
}
The function calculates the bestMove among all possible moves and then asks the game board script to place the corresponding token on the grid.
You can use Coroutine to do a heavy task and avoid freezing.
Change your method return type to IEnumerator
IEnumerator Heavy()
{
// some real heavy task
for (int i = 1; i < 10000000; i++)
{
balh();
yield return new WaitForEndOfFrame();
}
}
And simply call it like this:
StartCoroutine(Heavy());
You just have to run it on a MonoBehaviour. that's it.
I am trying to detect an overlap between the player and a ladder in a static group. I have a variable "this.onLadder", which is set to false in the constructor and then I am setting it to true when there is an overlap, but for some reason it changes back to false again in my update function, so when the player is overlapping with the ladder it keeps changing between true and false. Can anyone help me figure out what I am doing wrong?
My constructor function looks like this:
constructor() {
super('scene1'); // key: scene1
this.score = 0;
this.gameOver = false;
this.onLadder = false;
this.isClimbing = false;
}
Here is my create function:
create() {
this.createPlatforms();
this.createLadders();
this.createPlayer();
this.createBackground();
this.createCursor();
this.createJumpButton();
this.cameras.main.setBounds(0, 0, 1024, 2048);
this.scoreText = this.add.text(16, 16, 'score: 0', { fontSize: '32px', fill: '#000' });
}
This is how I am creating the ladder:
createLadders() {
this.ladders = this.physics.add.staticGroup();
this.ladders.create(300, 510, 'ladder');
this.ladders.setDepth(1);
}
and in my createPlayer function I have added:
this.physics.add.overlap(this.player, this.ladders, this.detectOverlap);
and the detectOverlap function just looks like this:
detectOverlap() {
this.onLadder = true;
console.log(`detect on ladder ${this.onLadder}`);
}
In my update function I am then trying to check if this.onLadder is true and then allow the player to climb, but it doesn't work because this.onLadder keeps returning false.
Thank you very much in advance!
Okay I have a little game going on Phaser with a slider which the player can move up or down:
As you can see, the slider is on a track which one would assume restricts where the slider can go. At the moment, this isn't the case and the slider can run right off the rail.
How can I detect if there's a slider track in the target location before moving the slider?
Here's where I'm creating the static groups for slider and slider track.
sliders = this.physics.add.staticGroup();
slider_tracks = this.physics.add.staticGroup();
Here's where the objects themselves are being added to the game:
add_slider: function (x, y, data) {
map.add_slider_track(x, y, data);
var slider = sliders.create(x, y, data.direction + '_slider');
for (var key in data) {
slider[key] = data[key];
}
},
add_slider_track: function (x, y, data) {
slider_tracks.create(x, y, data.direction + '_track');
},
And here's the functions which move it:
hitSlider: function (player, slider) {
if (slider.direction == 'vertical') {
if (player.body.onFloor() && player.slamming) {
interaction.moveSliderDown(slider)
} else if (player.body.onCeiling()) {
interaction.moveSliderUp(slider);
}
}
player.slamming = false;
},
moveSliderUp: function (slider) {
slider.setY(slider.y - block_size);
slider.body.position.y = (slider.y - (block_size / 2));
player.setVelocityY(100);
},
moveSliderDown: function (slider) {
slider.setY(slider.y + block_size);
slider.body.position.y = (slider.y - (block_size / 2));
}
I've tried using slider_track.getFirst (https://rexrainbow.github.io/phaser3-rex-notes/docs/site/group/) but it seems to change the location of a given piece of track, not just detect if there's one there.
Just to don't let this question without answer as we normally start a chat, effectively I see in the js/slider_actions.js the solution but I can just say you can use velocity but seriously my level of coding even if I am for a long time in the Phaser community is lower than yours ;)
sliderTrackRight: function (slider) {
track = slider_tracks.children.entries.find(
function (track) {
return (
track.body.y == slider.body.y &&
track.body.x == (slider.body.x + block_size) &&
track.direction == 'horizontal'
)
}
);
return (typeof track != 'undefined');
},
I have a grid-based top-down game with arcade physics and I'd like my player to move precisely between grid positions. But how can I do this?
I'm moving the player now on keydown using velocity, then resetting the velocity to 0 on update so there's no inertia.
function update(){
this.player.body.velocity.x = 0
this.player.body.velocity.y = 0
if(this.keyIsLeft){
this.player.body.velocity.x -= 200
}
else if(this.keyIsRight){
this.player.body.velocity.x += 200
}
else if(this.keyIsUp){
this.player.body.velocity.y -= 200
}
else if(this.keyIsDown){
this.player.body.velocity.y += 200
}
But how can I get the player to only move a square (or half square) at a time?
The ideal movement is shown here in this Lolo game, where at any given time the player is on a grid or half-grid space: https://www.youtube.com/watch?v=QQKScIJYUxU&t=5m30s
I can't just set the x and y position or use tweening because I need to keep arcade physics, and those adjustments interfere with them.
Updated:
Here is my updated Answer to solve this case.
I implemented this method based on the example provided by Phaser.
The key part to making this fixed movement happen is to disable the keyboard input while the item is moving.
Let's say if you pressed left key, the player is moving towards left. While the player starts moving, you set a variable notMoving to false, which notifies the update function to not take any cursor inputs. After a timeout, let's say 1000ms, you can set the variable notMoving to true. Then the update function will continue take the cursor input.
Here is the example code snippet:
function create ()
{
cursors = this.input.keyboard.createCursorKeys();
player = this.physics.add.image(400, 300, 'block');
player.setCollideWorldBounds(true);
player.setData('notMoving', true);
}
function setfixedMovement(velocity, direction) {
if (direction === 'up') {
player.setVelocityY(-velocity);
} else if (direction === 'down') {
player.setVelocityY(velocity);
} else if (direction === 'left') {
player.setVelocityX(-velocity);
} else {
player.setVelocityX(velocity);
}
player.setData('notMoving', false);
setTimeout(() => {
player.setData('notMoving', true);
}, 1000);
}
function update () {
if (player.getData('notMoving')) {
player.setVelocity(0);
if (cursors.left.isDown) {
setfixedMovement(300, 'left');
} else if (cursors.right.isDown) {
setfixedMovement(300, 'right');
}
if (cursors.up.isDown) {
setfixedMovement(300, 'up');
} else if (cursors.down.isDown) {
setfixedMovement(300, 'down');
}
}
}
I put the phaser example link in the previous answer. If you edit the example and replace the part of example code with the snippet I provided above, you can see it working as you expected.
Previous Answer:
I think what this phaser example does exactly what you want to do
In short,
in each update, set the velocity to 0,
then detect the check the cursor key status and set the velocity accordingly
the following code is copied from Official Phaser 3 Example
function update ()
{ player.setVelocity(0);
if (cursors.left.isDown)
{
player.setVelocityX(-300);
}
else if (cursors.right.isDown)
{
player.setVelocityX(300);
}
if (cursors.up.isDown)
{
player.setVelocityY(-300);
}
else if (cursors.down.isDown)
{
player.setVelocityY(300);
}
}
Here is the link to the example
https://labs.phaser.io/view.html?src=src\input\keyboard\cursor%20keys.js