Blog Archives

Pool game: potting balls and improved rebounding

In this article we continue the development of a pool game in Alice 2.2. This article continues on from the first two stages described in https://programminginalice.wordpress.com/2011/12/03/developing-a-pool-game-in-alice-2-2.

Stage 3: Potting balls

In the third stage of the game development support for potting balls was added. In developing this support we were faced with the same problem that we had with detecting collisions with the cushions, i.e. the pockets are not defined separately. We choose a similar solution, however in this case we use circles from the shapes collection of the local gallery as dummy markers for the pockets. These circles were resized and moved into place. A picture of the dummy markers is shown below.

Dummy markers for pool table pockets

Having set up the dummy markers for the pockets, we can use  the is within threshold to check whether a ball is within a certain distance of one of the pockets. When a ball enters one of the dummy markers for the pockets we change the isShowing variable for that ball to false so that the ball vanishes. A future enhancement for this situation is to get the ball to drop as it enters the pocket.

The code for this stage of development is available for download from http://www.alice.org/community/showthread.php?p=44064#post44064

Stage 4: Calculating Rebound Angles

In stage 4 the main aim was to implement realistic rebounding off of the cushions. In particular we wanted the angle of reflection to equal the angle of incidence. The tricky part here is to determine the angle of incidence, i.e. the angle at which the ball collides with the cushion. To calculate this we need to know what angle the ball is travelling at when it hits the cushion. To calculate this angle we need to know the current position of the ball and the previous position of the ball (where it first started travelling in a straight line towards the cushion). From these two points we calculate the change in the x-coordinates and change in y-coordinates and hence the angle of travel.

Stage 5:Documentation

This stage was fairly minor, but important none-the-less. In this stage I added some documentation to my code. Yes I should have been doing this all along, but given the rather rapid and experimental nature of the early stages I didn’t deem it as essential. The documentation is still very sketchy, but should give some insight into what the main methods and functions are doing.

Here’s a link to the code which includes the stage 4 calculation of rebounding angles and the added documentation at no extra cost http://www.alice.org/community/showthread.php?p=44085#post44085.

Developing a pool game in Alice 2.2

Introduction

In this article I will describe the development of a pool game in Alice. Because the game is quite complicated I will describe the development in a number of stages.

Upon starting the development I decided to simplify things a bit. In particular I decided to work with only two balls – the cue ball and the one ball. This is always a good policy when developing code – start simple then build up. If I can develop code that works for two balls, then I can investigate whether it generalised to deal with many balls.

Stage 1: Ball Collision

The plan for the first stage of development was to implement collision detection between two balls. To do this I needed some way of moving the cue ball. Therefore the requirements for the first stage of development became:

  • The user shall be able to aim and move the cue ball
  • The program shall detect collision between the cue ball and the one ball and react in a suitable manner.

To represent the aiming of the cue ball I added a cue. The user is able to rotate the cue using while key is pressed events. In addition I added support for varying the power of the shot. Pressing the down arrow pulled the cue backwards and hence increased the power of the shot. Pressing the up arrow decreased the power of the shot.

Detecting collision between the cue ball and the one ball is fairly straightforward. To do this we use the cueball within threshold of  function to check whether the cueball and one ball are touching. This check is done within a when condition becomes true event, so that collision is continuously being monitored. For this stage I went with a simple reaction to collision – the cue ball moves backwards and the one ball moves forwards.

Initial setup for pool game

The code for the first stage is available for download at http://www.alice.org/community/showthread.php?p=44054#post44054

Stage 2: Bouncing off cushions

In this stage I planned to add boundary detection for the cushions of the pool table.  Furthermore I wanted to make the reaction of colliding balls more realistic, i.e. make them move at a realistic angle.

In order to implement boundary detection I need a way of defining the cushions of the pool table. As it happens the pool table is defined as a single object, so the cushions are not defined. In order to define the boundaries of the cushions I placed four dummy objects along the cushions. This is similar to the idea presented in the video below, however in this case I chose not to shrink the dummy objects.

The dummy objects on the side cushions were position such that the right hand direction markers were facing directly out from the side of the table. Similarly the dummy objects on the end cushions were position so that the forward direction markers were facing out from the table. This is illustrated in the following picture.

These dummy objects can then be used to detect collision with the cushions. For the side cushions a collision occurs when the ball is not to the left of the dummy object. For the end cushions, we test whether the ball is not behind the dummy object. These checks were placed in a function, which is then called within a method, reboundOffCushion,  which implements rebounding of balls off of the cushions. This method is called within a while world is running event, which continually checks for collisions. In this version of the code a ball that collides with a cushion is turned at an angle of 90 degrees.

Improved ball collision

The other main enhancement during this stage of development was to improve the collision between balls. In the first version the one ball travelled directly forwards, while the cue ball travelled backwards regardless of what angle the balls collided. To improve ball collision we turn each ball so that it is pointing towards the centre of the other ball. We then rotate each ball 180 degrees. Probably not perfect physics, but it does provide a reasonable effect, allowing the player to play straight shots as well as cut shots.

The code for this second stage is available for download at http://www.alice.org/community/showthread.php?p=44057#post44057

Testing Alice code

Unit testing

Software testing is a critical part of the software development lifecycle. By performing systematic and comprehensive software testing we gain some level of trust in our software. Of course software testing provides us with no guarantees that our code if bug free, but if done correctly it should lower the number of bugs.

Unit testing, in which individual functions or methods are tested in isolation using a broad coverage of tests, is a standard testing technique. Most programming languages support a unit testing framework referred to in broad terms as xUnit. In xUnit frameworks, individual test cases are defined by giving the test inputs and the expected result. Tests are then typically run automatically and a report generated indicating the number of tests that passed. By rerunning tests each time changes are made to functions/methods we are able to check whether or not the changes have introduced new bugs – this process is referred to as regression testing.

Testing in Alice

The Alice programming environment does not provide any built in support for unit testing. However it is relatively easy to provide support for unit testing of functions in Alice. To demonstrate this I implemented a small number of test cases for a dice poker game. The dice poker game randomly generates 5 dice rolls, then checks whether the 5 dice correspond to certain combinations, such as a straight, full house, three of a kind etc.

To check these combinations a number of functions have been developed, for example the function isStraight, checks whether the 5 dice correspond to a straight (five consecutive numbers). These functions are perfect candidates for unit testing. They are quite simple conceptually and therefore it is easy to generate test cases for them; however the implementation of these functions is relatively complex.

To implement unit testing in Alice we can implement assert functions as used in xUnit. The assertTrue function, shown below, takes a test number and the actual result of the function being tested. In this case the test will pass if the actual result is true, i.e. the expected result of the function is true. If the actual result is false, then the test fails. The result of the test is printed out.

assert True functionOther assert functions, such as assertFalse and assertEquals can be developed in a similar manner. The use the assert functions we include a unit tests method. This method can be run whenever changes are made to the functions being tested. Whilst this is not an automated process like it would be in other programming languages, it still provides us with a reasonable framework for running unit tests. In the unit test method shown below there are two test inputs that can be used to test different results. Four test cases are defined, each calling either the assertTrue or assertFalse function. To conduct thorough testing we would have a lot more test cases with a variety of test inputs. We may also split the test cases for the different functions into separate test methods, rather than putting all the tests in one method.

Unit tests in Alice

The following video tutorial gives are more in depth description of the process of setting up the test cases. However it should be noted that solution presented here is an improvement on the one shown in the video.

If you wish to download a copy of the code, then go to the following link http://www.alice.org/community/showthread.php?p=43808#post43808

Tutorial: A turned based combat game in Alice

Introduction

This tutorial describes how to implement a simple turned-based fighting game in Alice. It is by no means complete, but it does cover the essentials. Note that the animations are awful – clearly not my forte – but that’s not the purpose. Instead the main focus is on the underlying logic. To setup the game I have introduced two main characters – a Knight and a Crispy Knight (yeah I’ve got no idea why they call it a Crispy Knight). I’ve also introduced two 3D text objects to represent the hit points of the two characters.

Turn-based fighting game

In this simple version the two characters each have a single attack move (a kick). The characters take it in turns to attack, using a “when key is pressed” event. When the attack is completed the program determines whether the attack was successful (i.e. whether it hit) and how much damage was done. Both of these are determined randomly. If damage is done, then the hitpoints of the wounded character are decreased.

Hitpoints

Hitpoints represent the lifeforce of the characters. When a character’s hitpoints are reduced to zero they are knocked out. To represent the hitpoints we introduce a hitpoints variable to each of the character objects. This is introduced by clicking on the properties tab of the character object and then clicking on create new variable. In order to update the value of the hitpoints variable, we need to introduce a method called decHitPoints.


knight.decHitPoints ( [123] damage)
No variables
knight.hitpoints set value to ( ( knight.hitpoints - damage ) )

Similarly we introduce a function called getHitPoints, which returns the current number of hit points. We also introduce a method to the world object to initialise the hit points of the two characters. We use random number generators to determine how many hitpoints each character has.


world.initialise ( )
No variables
knight.hitpoints set value to 0
Loop 10 times times
knight.hitpoints set value to ( ( knight.hitpoints + ( random number minimum = 1 maximum = 10 integerOnly = true ) ) )
print knight.hitpoints
Knight_HP.updateHP ( knight.getHitPoints )
Knight_HP set isShowing to true duration = 0.02 seconds
crispyKnight.hitpoints set value to 0
Loop 10 times times
crispyKnight.hitpoints set value to ( ( crispyKnight.hitpoints + ( random number minimum = 1 maximum = 10 integerOnly = true ) ) )
print crispyKnight.hitpoints
CK_HP.updateHP hp = crispyKnight.hitpoints
CK_HP set isShowing to true duration = 0.02 seconds
Knight_HP set color to (0, 1, 0) duration = 0.02 seconds

Attacks

The next step is to program the attack moves for each of the characters. In this version each character has a single basic attack, but the code could be extended to include multiple different attacks, with each attack doing different damage and having a different likelihood of hitting. Each attack has a certain chance of hitting – for the kicking attacks we use a 60% chance of hitting using the random probability function. If an attack hits, it does a random amount of damage, the kick does 2-5 hit points (again this could be varied for different attacks). At the end of the attack the turn is toggled so that the other character gets to have an attack. To keep track of whose turn it is we use a boolean valued variable called knightsturn, which is initially set to true (meaning that the knight has the first attack). Note that the Knight’s kick attack will only be activated if it is the Knight’s turn – the isKnightsTurn function looks up the current value of the knightsturn variable.


knight.kick ( )
damage = 1
If ( world.isKnightsTurn )
Knight_HP set color to (1, 1, 1) duration = 0.02 seconds
knight.rightLeg turn backward 0.25 revolutions duration = 0.5 seconds
knight.rightLeg turn forward 0.25 revolutions duration = 0.5 seconds
If ( choose true 0.6 (60%) of the time )
damage set value to ( ( ( random number minimum = 1 maximum = 4 integerOnly = true ) + 1 ) )
crispyKnight.decHitPoints damage = damage
CK_HP.updateHP ( crispyKnight.getHitPoints )
Else
Do Nothing
world.toggleTurn
print crispyKnight.hitpoints
CK_HP set color to (0, 1, 0) duration = 0.02 seconds
Else
Do Nothing

Events

An event is included that initialises the hit points when the world first starts.Two “when key is pressed” events are also included that call the kick attacks.

When the world starts
Do: world.initialise

When J is typed
Do: knight.kick

When A is typed
Do: crispyKnight.kick

The following video tutorial sums up the main steps in developing a turn-based fighting game.

Tutorial: walking animation in Alice 2.2

The Alice 2.2 programming environment includes the heBuilder and sheBuilder objects that allow programmers to custom build characters. The other advantage of these objects is that they include a number of predefined animations, including a walking animation, together with several other animations. Now I’m a programmer, not an animator, so I welcome any pre-existing animations, and in my opinion the animations that come with these builder objects are pretty good.

The heBuilder and sheBuilder classes can be found in the gallery: look under Home > Local Gallery > People. The builder classes then enable you to build custom characters, by selecting various features. The interface is fairly straightforward, and is like the character builder for the Wii (not as many options though).

Alice shebuilder class

Once you have created a custom character, you can then make use of the pre-defined methods. Methods include a walking animation, together with several “emotion” animations, such as angry, confused, happy etc.

The following video tutorial demonstrates how these methods can be used. To do this we use several “when key is pressed” events to control the character. To get the character to walk forward we combine the walking animation with the move forward method.

Walking while key is pressed

Programming the character to walk when the key is pressed is fairly straightforward and is described in the video shown above. However programming the character to walk while the key is pressed is not so easy. If we try to call the same walk forward method that we use for the “when key is pressed event” the program generates an exception. This is because the while key is pressed event stops executing the code that it executes while the key is pressed as soon as the key is released. This is problematic for the walk method – terminating the method mid-way through leads to this execution. What we need is some way to finish executing the code in the walk method.

To do this we introduce a simple two-state finite state machine. The states for this FSM are walking and idle. Whenever the FSM is in the walking state, we run the walking animation. Whenever the FSM is in the idle state the walking animation is not run. To represent the state we use a boolean valued variable, called walking. The variable is true when the FSM is in the walking state and false otherwise. If there were more than two states we would need to represent the state in another way – perhaps using a string.

Putting this all together, we use the “While key is pressed event”. At the beginning of event we change the walking state to true. This triggers the walking animation action. During the key press event the character moves forward. At the end of the key press event the walking state is changed to false. At this point the walking animation action is stopped, but not until the code for the current call is completed, thus avoiding the termination of code mid-way through.

Ok, that is probably all a bit convoluted, so lets go to the video.

Tutorial: collision detection

Introduction

Collision detection is a common feature of many animation tools, so a question that sometimes is asked when students first start using Alice is “where is built-in support for collision detection?”. The short answer is that there isn’t any. Remember that Alice is a programming environment in which students can develop animations, as opposed to a purpose built animation tool.  However, because it is a programming environment, Alice gives programmers the ability to readily develop their own support for collision detection. This tutorial provides a description of how such collision detection support can be implemented.

The Alice World

The world for this tutorial consists of a Humvee van and a number of obstacles. Event handling methods and event handlers have already been implemented that allow the user to move the car around the world. For example the code for driving the Humvee forward is as follows. A “Do together” block is used to drive the move the car forward and at the same time rotate the wheels.

Code for driving Humvee forward

Setting up collision detection

To set up collision detection and collision avoidance we begin by adding a method, called collision, to the world object  that detects and reacts to collisions. We begin by setting this up for a single obstacle, in this case a building and then extend the code so that we can handle multiple obstacles.  To detect a collision we use the “is within threshold of” function from the humvee object. This is used as the conditional of an if-then-else statement. If the condition is true, then the humvee reacts to the collision by moving backwards a short distance.

When using the “is within threshold of” function, we need to bear in mind that the function is measuring the distance between the centre of the Humvee and the centre of the obstacle. A collision with the side of the obstacle will therefore occur when the distance between the centres is half of the obstacle width + half of the Humvee depth. This distance will when the Humvee is approaching from a different direction, e.g. from the front of the building (in which case we might use the half of the obstacle depth). For this tutorial we just use the above calculation, but we could include a more sophisticated check by determining which direction the Humvee is approaching the obstacle from using the “is in front of” and similar functions.

After developing the collision method, we create a “while world is running” event handler. This event handler will call the collision method, such that whenever a collision is detected the Humvee will react and move backwards.

Dealing with multiple obstacles

So far we can only handle a single obstacle. We could of course develop similar methods to handle the other obstacles, but the DRY (don’t repeat yourself) principle suggests we should find a better way of doing this. Rather than repeating the code for the other obstacles, what we will do is generalise the existing code to handle many obstacles. To do this we use an list variable to represent the collection of all obstacles and then use the “for all do together” construct to implement collision detection and avoidance within a single method.

Video Tutorial

The following video tutorial provides a step-by-step description of the development of the collision detection capabilities.