This is an extremely simple actor. We start with the ball picture and set its origin to the centre of the image. However this does not give us any behavior at all. Simply making an instance of this class will result in a pretty boring actor.
Heartbeat
The next step is to look at our host script and add a heartbeat. This will be done using the on_tick() event umajin provides for every frame. We will augment this to include the time between this and the last frame so that the animation can appear the same on different speed machines.
[Host]
object items[]
int otime = system.time()
method on_tick()
real timestep = (otime-system.time()) / 10.0
otime = system.time()
int a=0
loop a<length(items)
raise items[a].tick(timestep)
a++
end
end
Now the beauty of this technique is that the raise command will try and find our special tick() method inside our actors. With this in mind I have added a few new properties to the ball. These are the x and y velocity, along with a damping factor which describes the amount of bounciness of our ball.
[Actor]
property real vx = 0.0
property real vy = 0.0
property real damping = 0.9
You will notice the tick method takes a timestep as a parameter. This is the aforementioned measure of elapsed time since the last tick call. So on a slower machine we should see more motion between ticks.
[Actor]
method tick(real timestep)
//vertical motion
.vy += gravity * timestep
.y += .vy * timestep
//bounce
if .y>worldy
.y = worldy
.vy = -.vy*.damping
.vx = .vx*0.95
end
//bounce animation
if .y>worldy-10 && .vy>4
.filename = "puppets/ball2.png"
else
.filename = "puppets/ball1.png"
end
//horizontal motion
.x += .vx * timestep
//bounce
if .x>worldx
.x = worldx
.vx = -.vx
end
if .x<0
.x = 0
.vx = -.vx
end
end
This code is surprisingly short for quite a fun behavior. Essentially the ball will first add the acceleration from gravity to its vertical velocity. Then it will update its position. Then it will check if it is below ground level and reverse its velocity allowing for our damping factor (e.g. bounce).
The bounce animation changes the ball image when we are within 10 pixels of the ground and the velocity is still high (e.g. we are bouncing).
Finally the vertical velocity updates the position and the checks for bounces against the sides of the environment.
Who’s got the Brains?
The next trick is to give our actors more than just a heartbeat, let’s give them some brains. Now I do take offence to the term AI = Artificial Intelligence. I like to think of the normal techniques developers use as AI = Artificial Instinct. We do occasionally develop algorithms or simulations that appear emergent… but that’s just normally the human brain making patterns and connections where they don’t really existing. We are certainly not going to attempting to simulate real intelligence with neural networks or similar techniques in this tutorial. I’ll settle for a puppy who responds to our mouse click, and to the other objects in the world (the ball).
[Actor]
method on_mouse_down(int x, int y, int mod)
if x>.native_width / 2.0
.vx += .scale_width * 4
else
.vx -= .scale_width * 4
end
.vy += 1
End
This code allows our puppy to feel the pinch. As we click on it there is a reaction where it jumps slightly in the air and away from our click. We do this by using the scale_width as an indication of direction. This means positive scale is facing forwards – and negative scale is facing backwards.
[Actor tick]
//point the puppy the right way
if .vx<0
.scale_width = 0.5
else
.scale_width = -0.5
end
Adding this code to the puppies tick even will result in ensuring the direction matches the current velocity and actual direction the puppy is travelling in.
Finally we can add a specific test to see if any balls are nearby.. and to react appropriately.
[Actor tick]
//react to other object
int a=0
loop a<length(items)
if items[a].typeof()=="puppet_ball"
puppet_ball b = items[a]
if abs(b.x - .x - .scale_width*150) < 20 && abs(b.y - .y - 20) < 30
b.vy += 10
.head.angle = 40
.head.angle = 0 in 500 tween linear
b.vx += .scale_width
end
end
a++
end
This code essentially checks to see if the puppy is near an object of type puppet_ball. If this is the case then the ball is thrown up, slightly away and the puppies head is animated to perform a slight tilt – or headbut.
Any Courage?
OK let’s see if we can add some behaviors that are more than just reactions to us or other objects.
We need to give the puppy some sense of self. We will start with the puppy having a random action. Perhaps wander around the scene or sit down. The trick with these additional behaviors is we need to be able to recover from these states when it reaches an interaction.
Next we want to add a simple AI trick which is a level. These can be used to great effect in games like the Will Wright games the SIMs. The concept is that sims have levels like sleep, hunger or entertainment which you can effect through your actions.
Let’s make the puppy level ‘boredom’. If it is high, then you have not been playing with it enough. If it is low, then it is happy.
If we can come up with some actions for both extremes then we can create an actor who appears to be more alive. (e.g. sit down when bored and jump when excited)